org.squashtest.tm.service.internal.hibernate.SquashEntityManagerFactoryBuilderImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.squashtest.tm.service.internal.hibernate.SquashEntityManagerFactoryBuilderImpl.java

Source

/**
 *     This file is part of the Squashtest platform.
 *     Copyright (C) 2010 - 2016 Henix, henix.fr
 *
 *     See the NOTICE file distributed with this work for additional
 *     information regarding copyright ownership.
 *
 *     This 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
 *     (at your option) any later version.
 *
 *     this software 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 this software.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.squashtest.tm.service.internal.hibernate;

import static org.squashtest.tm.domain.jpql.SessionFactoryEnhancer.FnSupport.EXTRACT_WEEK;
import static org.squashtest.tm.domain.jpql.SessionFactoryEnhancer.FnSupport.GROUP_CONCAT;
import static org.squashtest.tm.domain.jpql.SessionFactoryEnhancer.FnSupport.STR_AGG;

import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.cfg.Configuration;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
import org.hibernate.service.ServiceRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.squashtest.tm.domain.jpql.SessionFactoryEnhancer;
import org.squashtest.tm.domain.jpql.SessionFactoryEnhancer.FnSupport;
import org.squashtest.tm.infrastructure.hibernate.UppercaseUnderscoreNamingStrategy;
import org.squashtest.tm.service.RepositoryConfig;

/**
 * <p>
 * Porting the former SquashSessionFactoryBean to the equivalent as a EntityManagerFactoryBuilder. Legacy comments
 * are included below. Note that some elements of the configuration had to be set there because 
 * we couldn't access the configuration from {@link RepositoryConfig}.</p>
 * 
 * <p>Also note that it is critical that the hibernate configuration is properly set before the session factory is created by 
 * the code in the super class : we cannot prostprocess the session factory afterward. This is why this class exists.</p>
    
 * 
 * <hr/>
 * 
 * <p>
 * Specialization of LocalSessionFactoryBean which registers a "group_concat" hsl function for any known dialect.
 * <p/>
 * Note : I would have inlined this class in #sessionFactory() if I could. But Spring enhances RepositoryConfig in
 * a way that the product of #sessionFactory() is expected to have a null-arg constructor. Yet, the default
 * constructor of an inner / anonymous class is a 1-param ctor which receives the outer instance. This leads to
 * arcane reflection errors (NoSuchMethodException "There is no no-arg ctor") in lines that seem completely unrelated
 *
 * @see #extendConfiguration(Configuration)
 * @see #configureFunctionSupport(String)
 * 
 * 
 * @author Gregory Fouquet
 * @author bsiri
 * @since 1.14.0
 */
public class SquashEntityManagerFactoryBuilderImpl extends EntityManagerFactoryBuilderImpl {

    private static final Logger LOGGER = LoggerFactory.getLogger(SquashEntityManagerFactoryBuilderImpl.class);

    public SquashEntityManagerFactoryBuilderImpl(PersistenceUnitDescriptor persistenceUnit, Map integrationSettings,
            ClassLoader providedClassLoader) {
        super(persistenceUnit, integrationSettings, providedClassLoader);
    }

    public SquashEntityManagerFactoryBuilderImpl(PersistenceUnitDescriptor persistenceUnit,
            Map integrationSettings) {
        super(persistenceUnit, integrationSettings);
    }

    @Override
    public Configuration buildHibernateConfiguration(ServiceRegistry serviceRegistry) {

        Configuration conf = super.buildHibernateConfiguration(serviceRegistry);

        return extendConfiguration(conf);

    }

    protected Configuration extendConfiguration(Configuration conf) {
        String dialect = conf.getProperty("hibernate.dialect");

        SessionFactoryEnhancer.registerExtensions(conf, configureFunctionSupport(dialect));

        conf.setNamingStrategy(new UppercaseUnderscoreNamingStrategy());
        conf.setInterceptor(new AuditLogInterceptor());

        return conf;
    }

    /**
     * Returns the extensions required by our supported dialects. As of Squash 1.13 extensions are : 
     * 
     * <ul>
     *    <li>Postgresql : 
     *       <ul>
     *          <li>string_aggr : maps our HQL version of group_concat to postgresql string_aggr</li>
     *          <li>extract_week : maps native HQL week(timestamp) to postgresql extract(week from timestamp) because Hibernate won't</li>
     *       </ul>
     *    </li>
     *    <li>Mysql, H2 :
     *       <ul>
     *          <li>group_concat : just maps our HQL version of group_concat to group_concat (same name in both database)</li>
     *       </ul>
     *    </li>
     *    <li>
     *    <li>default (for not officially supported DBs) : 
     *       <ul>
     *          <li>group_concat : a short in the dark and hope that function group_concat exists in the end target</li>
     *       </ul>
     * </li>
     * </ul>
     * 
     * @param dialectProp value of the dialect Hibernate property
     */

    private FnSupport[] configureFunctionSupport(String dialectProp) {
        String dialect = ConfigurationHelper.resolvePlaceHolder(StringUtils.defaultString(dialectProp))
                .toLowerCase();

        if (StringUtils.contains(dialect, "postgresql")) {
            return new FnSupport[] { STR_AGG, EXTRACT_WEEK };
        } else {
            if (!StringUtils.contains(dialect, "h2") && !StringUtils.contains(dialect, "mysql")) {
                LOGGER.warn(
                        "Selected hibernate Dialect '{}' is not known to support the sql function 'group_concat()'. Application will certainly not properly work. Maybe you configured a wrong dialect ?",
                        dialectProp);
            }

            return new FnSupport[] { GROUP_CONCAT };
        }
    }

}