org.libreplan.business.common.daos.GenericDAOHibernate.java Source code

Java tutorial

Introduction

Here is the source code for org.libreplan.business.common.daos.GenericDAOHibernate.java

Source

/*
 * This file is part of LibrePlan
 *
 * Copyright (C) 2009-2010 Fundacin para o Fomento da Calidade Industrial e
 *                         Desenvolvemento Tecnolxico de Galicia
 * Copyright (C) 2010-2011 Igalia, S.L.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * 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 Affero 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/>.
 */

package org.libreplan.business.common.daos;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import org.apache.commons.lang3.Validate;
import org.hibernate.Hibernate;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StaleObjectStateException;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.libreplan.business.common.BaseEntity;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.common.exceptions.ValidationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

/**
 * An implementation of <code>IGenericDao</code> based on Hibernate's native API.
 * Concrete DAOs must extend directly from this class.
 * This constraint is imposed by the constructor of this class that must infer the type of the
 * entity from the declaration of the concrete DAO.
 *
 * This class autowires a <code>SessionFactory</code> bean and allows to implement DAOs with Hibernate's native API.
 * Subclasses access Hibernate's <code>Session</code> by calling on <code>getSession()</code> method.
 * Operations must be implemented by catching <code>HibernateException</code>
 * and rethrowing it by using <code>convertHibernateAccessException()</code> method.
 * See source code of this class for an example.
 *
 * @author Fernando Bellas Permuy <fbellas@udc.es>
 * @param <E>
 *            Entity class
 * @param <PK>
 *            Primary key class
 */
public class GenericDAOHibernate<E extends BaseEntity, PK extends Serializable> implements IGenericDAO<E, PK> {

    private Class<E> entityClass;

    @Autowired
    private SessionFactory sessionFactory;

    @SuppressWarnings("unchecked")
    public GenericDAOHibernate() {
        this.entityClass = (Class<E>) ((ParameterizedType) getClass().getGenericSuperclass())
                .getActualTypeArguments()[0];
    }

    public GenericDAOHibernate(Class<E> entityClass) {
        Validate.notNull(entityClass);
        this.entityClass = entityClass;
    }

    protected Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    public Class<E> getEntityClass() {
        return entityClass;
    }

    /**
     * It's necessary to save and validate later.
     *
     * Validate may retrieve the entity from DB and put it into the Session, which can eventually lead to
     * a NonUniqueObject exception.
     * Save works here to reattach the object as well as saving.
     */
    public void save(E entity) throws ValidationException {
        getSession().saveOrUpdate(entity);
        entity.validate();
    }

    public void saveWithoutValidating(E entity) {
        getSession().saveOrUpdate(entity);
    }

    public void reattachUnmodifiedEntity(E entity) {
        if (Hibernate.isInitialized(entity) && entity.isNewObject()) {
            return;
        }
        // TODO resolve deprecated
        getSession().lock(entity, LockMode.NONE);
    }

    public E merge(E entity) {
        return entityClass.cast(getSession().merge(entity));
    }

    public void checkVersion(E entity) {

        /* Get id and version from entity */
        Serializable id;
        Long versionValueInMemory;

        try {

            Method getIdMethod = entityClass.getMethod("getId");
            id = (Serializable) getIdMethod.invoke(entity);

            if (id == null) {
                return;
            }

            Method getVersionMethod = entityClass.getMethod("getVersion");
            versionValueInMemory = (Long) getVersionMethod.invoke(entity);

            if (versionValueInMemory == null) {
                return;
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        /* Check version */
        Long versionValueInDB = (Long) getSession().createCriteria(entityClass).add(Restrictions.idEq(id))
                .setProjection(Projections.property("version")).uniqueResult();

        if (versionValueInDB == null) {
            return;
        }

        if (!versionValueInMemory.equals(versionValueInDB)) {
            throw new StaleObjectStateException(entityClass.getName(), id);
        }

    }

    public void lock(E entity) {
        // TODO resolve deprecated
        getSession().lock(entity, LockMode.UPGRADE);

    }

    @SuppressWarnings("unchecked")
    @Transactional(readOnly = true)
    public E find(PK id) throws InstanceNotFoundException {

        E entity = (E) getSession().get(entityClass, id);

        if (entity == null) {
            throw new InstanceNotFoundException(id, entityClass.getName());
        }

        return entity;
    }

    public E findExistingEntity(PK id) {

        try {
            return find(id);
        } catch (InstanceNotFoundException e) {
            throw new RuntimeException(e);
        }

    }

    public boolean exists(final PK id) {

        return getSession().createCriteria(entityClass).add(Restrictions.idEq(id)).setProjection(Projections.id())
                .uniqueResult() != null;

    }

    public void remove(PK id) throws InstanceNotFoundException {
        getSession().delete(find(id));
    }

    @SuppressWarnings("unchecked")
    @Override
    @Transactional(readOnly = true)
    public <T extends E> List<T> list(Class<T> klass) {
        return getSession().createCriteria(klass).list();
    }

    @Override
    public void flush() {
        getSession().flush();
    }

    @Override
    @Transactional
    public void reattach(E entity) {
        getSession().saveOrUpdate(entity);
    }

}