Package at.ipsquare.commons.hibernate

Source Code of at.ipsquare.commons.hibernate.DefaultHibernateRepository

/**
* Copyright (C) 2013 Matthias Langer
*
* 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 at.ipsquare.commons.hibernate;

import java.lang.ref.WeakReference;
import java.sql.Driver;
import java.util.Map;

import net.jcip.annotations.ThreadSafe;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import at.ipsquare.commons.core.interfaces.ExecutionError;
import at.ipsquare.commons.core.interfaces.UnitOfWork;
import at.ipsquare.commons.core.util.Classes;

import com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.google.inject.Singleton;

/**
* Default {@link HibernateRepository} implementation.
*
* @since 2.0.0
* @author Matthias Langer
*/
@Singleton
@ThreadSafe
public class DefaultHibernateRepository implements HibernateRepository
{
    private static final Logger log = LoggerFactory.getLogger(DefaultHibernateRepository.class);
   
    private static final
        Map<Class<? extends DefaultHibernateRepository>, WeakReference<? extends DefaultHibernateRepository>>
            instanceMap = Maps.newHashMapWithExpectedSize(2);
            
    private final SessionFactory sessionFactory;
    private final ThreadLocal<Session> currentSession = new ThreadLocal<Session>();
    private final ThreadLocal<UnitOfWork<?>> currentUnitOfWork = new ThreadLocal<UnitOfWork<?>>();
   
   
    @Inject
    public DefaultHibernateRepository(HibernateConfiguration hibernateCfg)
    {
        synchronized(instanceMap)
        {
            WeakReference<? extends DefaultHibernateRepository> ref = instanceMap.get(getClass());
            if(ref != null)
            {
                DefaultHibernateRepository other = ref.get();
                if(other != null && !other.isClosed())
                {
                    throw new IllegalStateException("Attempting to create an instance of " + getClass().getSimpleName() + " while " +
                        "another instance that has not yet been closed is still weakly reachable. " +
                        "You are not meant to have more than one open repository for the same underlying DB resource. " +
                        "Plese read the documentation and fix your code.");
                           
                }
            }

            instanceMap.put(getClass(), new WeakReference<DefaultHibernateRepository>(this));
        }

        sessionFactory = buildSessionFactory(hibernateCfg);
    }
   
    public <T> T executeUnitOfWork(UnitOfWork<T> work)
    {
        if(work == null)
            throw new NullPointerException();
       
        if(currentUnitOfWork.get() != null)
        {
            log.info("Executing " + work + " within already running " + currentUnitOfWork.get() + ".");
            try
            {
                return work.execute();
            }
            catch(Exception e)
            {
                log.warn(exceptionLogMessage(work), e);
                throw new ExecutionError(e);
            }
        }
       
        log.info("Executing " + work + ".");
        Session session = session();
        currentSession.set(session);
        currentUnitOfWork.set(work);
       
        session.beginTransaction();
        try
        {
            T result = null;
            try
            {
                result = work.execute();
            }
            catch(Exception e)
            {
                log.warn(exceptionLogMessage(work), e);
               
                Transaction tx = getActiveTransaction(session);
                if(tx != null)
                    tx.rollback();
                throw new ExecutionError(e);
            }
           
            Transaction tx = getActiveTransaction(session);
            if(tx != null)
                tx.commit();
            return result;
        }
        finally
        {
            try
            {
                log.info("Closing " + work + ".");
               
                /*
                 * TODO (mla):
                 *  Eventually issue a warning if the session is already closed.
                 */
                session.close();
            }
            finally
            {
                currentSession.set(null);
                currentUnitOfWork.set(null);
            }
        }
    }
   
    @Override
    public void close()
    {
        sessionFactory.close();
    }
   
    @Override
    public boolean isClosed()
    {
        return sessionFactory.isClosed();
    }
   
    private static String exceptionLogMessage(UnitOfWork<?> work)
    {
        return "Executing " + work + " resulted in an exception.";
    }
   
    private static Transaction getActiveTransaction(Session session)
    {
        Transaction tx = session.getTransaction();
        if(tx != null && tx.isActive())
            return tx;
        return null;
    }
   
    public Session currentSession()
    {
        if(currentUnitOfWork.get() == null)
            throw new IllegalStateException("Attempting to access the current session without a UnitOfWork.");
       
        if(currentSession.get() == null)
            throw new AssertionError("Should be impossible.");
       
        return currentSession.get();
    }
   
    private Session session()
    {
        if(currentSession.get() != null)
            return currentSession.get();
        return sessionFactory.openSession();
    }
   
    private static SessionFactory buildSessionFactory(HibernateConfiguration hibernateCfg)
    {
        Configuration nativeCfg = toNativeHibernateConfiguration(hibernateCfg);
        ServiceRegistryBuilder builder = new ServiceRegistryBuilder();
        builder.applySettings(nativeCfg.getProperties());
        return nativeCfg.buildSessionFactory(builder.buildServiceRegistry());
    }
   
    private static Configuration toNativeHibernateConfiguration(HibernateConfiguration hibernateCfg)
    {
        Configuration cfg = new Configuration();
        for(Class<?> domainClass : hibernateCfg.getDomainClasses())
            cfg.addAnnotatedClass(domainClass);
       
        cfg.setProperty("hibernate.connection.username", hibernateCfg.getDbUser());
        cfg.setProperty("hibernate.connection.password", hibernateCfg.getDbPass());
        cfg.setProperty("hibernate.connection.url", hibernateCfg.getDbConnectionUrl());
        cfg.setProperty("hibernate.connection.driver_class", hibernateCfg.getDbDriverClass().getCanonicalName());
        cfg.setProperty("hibernate.hbm2ddl.auto", hibernateCfg.getHbm2dllAuto().toString());
       
        if(hibernateCfg.getProperties() != null)
        {
            for(Map.Entry<String, String> entry : hibernateCfg.getProperties().entrySet())
                cfg.setProperty(entry.getKey(), entry.getValue());
        }
       
        explicitlyInitializeDriverClass(hibernateCfg.getDbDriverClass());
        return cfg;
    }
   
    /**
     * This method makes sure that the database driver is properly initialized.
     *
     * @see HibernateConfiguration#getDbDriverClass()
     */
    private static void explicitlyInitializeDriverClass(Class<? extends Driver> clazz)
    {
        try
        {
            Classes.forName(clazz.getName());
        }
        catch(ClassNotFoundException e)
        {
            throw new RuntimeException("Could not load database driver.", e);
        }
    }
}
TOP

Related Classes of at.ipsquare.commons.hibernate.DefaultHibernateRepository

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.