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

org.nuiton.topia.persistence.util.TopiaUtil Maven / Gradle / Ivy

The newest version!
package org.nuiton.topia.persistence.util;

/*
 * #%L
 * ToPIA Extension :: API
 * %%
 * Copyright (C) 2018 - 2022 Ultreia.io
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSet;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Table;
import org.hibernate.resource.transaction.spi.TransactionStatus;
import org.nuiton.topia.persistence.SchemaValidationTopiaException;
import org.nuiton.topia.persistence.TopiaException;
import org.nuiton.topia.persistence.internal.HibernateProvider;
import org.nuiton.topia.persistence.support.TopiaHibernateSupport;

import java.io.Closeable;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

/**
 * TODO-fdesbois-20100507 : Need javadoc + translations for existing methods.
 *
 * @author Benjamin Poussin - [email protected]
 * @author Tony Chemit - [email protected]
 */
public class TopiaUtil {
    private static final Logger log = LogManager.getLogger(TopiaUtil.class);

    /**
     * Test si une entite donnee correspondant a une configuration existe en
     * base.
     *
     * @param configuration la configuration hibernate
     * @param entityName    le nom de l'entite a tester
     * @return true si le schema de la table existe
     */
    public static boolean isSchemaExist(Configuration configuration, Metadata metadata, String entityName) {

        ConnectionProviderSupplier connectionProviderSupplier = new ConnectionProviderSupplier(configuration);

        boolean exist = false;
        try {
            PersistentClass classMapping = metadata.getEntityBinding(entityName);
            if (classMapping == null) {
                if (log.isInfoEnabled()) {
                    for (PersistentClass persistentClass : metadata.getEntityBindings()) {
                        log.info("available mapping " + persistentClass.getClassName());
                    }
                }
                throw new IllegalArgumentException("could not find entity with name " + entityName);
            }
            Table testTable = classMapping.getTable();

            if (testTable == null) {
                throw new IllegalArgumentException(
                        "could not find entity with name " + entityName);
            }

            ConnectionProvider connectionProvider = connectionProviderSupplier.get();

            Connection connection = null;
            try {
                connection = connectionProvider.getConnection();

                ResultSet tables = connection.getMetaData().getTables(testTable.getCatalog(), testTable.getSchema(), null, null);
                while (tables.next()) {
                    String currentTableName = tables.getString("TABLE_NAME");
                    if (currentTableName.equalsIgnoreCase(testTable.getName())) {
                        exist = true;
                    }
                }
                tables.close();

            } finally {
                connectionProvider.closeConnection(connection);
            }

        } catch (SQLException e) {
            log.error("Cant connect to database", e);
        } finally {
            try {
                connectionProviderSupplier.close();
            } catch (IOException e) {
                log.error("Cant close connection provider", e);
            }
        }

        return exist;
    }

    public static void warnOnAutomaticSchemaOperationRisk(Configuration configuration) {

        if (log.isWarnEnabled()) {
            String hbm2ddl = configuration.getProperties().getProperty(AvailableSettings.HBM2DDL_AUTO);
            if (ImmutableSet.of("update", "create", "create-drop").contains(hbm2ddl)) {
                log.warn(String.format("Be careful, you are about to let Hibernate automatically create or update " +
                                               "your database schema. [%s=%s]", AvailableSettings.HBM2DDL_AUTO, hbm2ddl));
            }
        }

    }

    /**
     * Test if the db associated to the given {@code configuration} contains any of
     * the dealed entities.
     *
     * @param configuration hibernate db configuration
     * @param metaData      hibernate metadata
     * @return {@code true} if there is no schema for any of the dealed entities,
     * {@code false} otherwise.
     * @since 2.5.3
     */
    public static boolean isSchemaEmpty(Configuration configuration, Metadata metaData) {

        warnOnAutomaticSchemaOperationRisk(configuration);

        ConnectionProviderSupplier connectionProviderSupplier = new ConnectionProviderSupplier(configuration);

        try {

            ConnectionProvider connectionProvider = connectionProviderSupplier.get();

            Connection connection = null;
            try {
                connection = connectionProvider.getConnection();

                for (PersistentClass persistentClass : metaData.getEntityBindings()) {

                    Table testTable = persistentClass.getTable();

                    ResultSet tables = connection.getMetaData().getTables(testTable.getCatalog(), testTable.getSchema(), null, null);
                    while (tables.next()) {
                        String currentTableName = tables.getString("TABLE_NAME");
                        log.trace("Scan table: " + currentTableName);
                        if (currentTableName.equalsIgnoreCase(testTable.getName())) {
                            if (log.isDebugEnabled()) {
                                log.debug("Existing table found " + testTable.getName() + " for entity " +
                                                  persistentClass.getClassName() + ", db is not empty.");
                            }

                            return false;
                        }
                    }
                    tables.close();
                }

            } finally {
                connectionProvider.closeConnection(connection);
            }

        } catch (SQLException e) {
            log.error("Cant connect to database", e);
        } finally {
            try {
                connectionProviderSupplier.close();
            } catch (IOException e) {
                log.error("Cant close connection provider", e);
            }
        }

        return true;
    }

    /**
     * Return hibernate schema name
     *
     * @param config of hibernate
     * @return schema name
     */
    public static String getSchemaName(Configuration config) {
        return config.getProperty(AvailableSettings.DEFAULT_SCHEMA);
    }

    public static Map convertPropertiesArrayToMap(Object... propertyNamesAndValues) throws IllegalArgumentException {
        int propertiesLength = propertyNamesAndValues.length;
        Preconditions.checkArgument(propertiesLength % 2 == 0,
                                    "Wrong number of argument "
                                            + propertiesLength
                                            + ", you must have even number.");
        Map properties = new LinkedHashMap<>();
        for (int i = 0; i < propertyNamesAndValues.length; ) {
            Object aPropertyName = propertyNamesAndValues[i++];
            Object value = propertyNamesAndValues[i++];
            Preconditions.checkArgument(
                    aPropertyName instanceof String,
                    "Argument at position [" + (i - 1) + "] " +
                            "should be a property name (says a String) but was " +
                            aPropertyName);
            properties.put((String) aPropertyName, value);
        }
        return properties;
    }

    public static Map convertPropertiesArrayToMap(
            String propertyName, Object propertyValue, Object... otherPropertyNamesAndValues) throws IllegalArgumentException {
        Map properties = new HashMap<>();
        properties.put(propertyName, propertyValue);
        properties.putAll(convertPropertiesArrayToMap(otherPropertyNamesAndValues));
        return properties;
    }

    /**
     * Hibernate 4.3.x compatible {@code Supplier}. The provider will choose the best way to find the
     * ConnectionProvider depending on the way is has been created.
     */
    public static class ConnectionProviderSupplier implements Supplier, Closeable {

        /**
         * If provided, the SessionFactory will be used instead of the StandardServiceRegistry
         */
        protected SessionFactory sessionFactory;

        /**
         * StandardServiceRegistry will be used if no SessionFactory is provided
         */
        protected StandardServiceRegistry standardServiceRegistry;

        protected ConnectionProvider connectionProvider;

        public ConnectionProviderSupplier(TopiaHibernateSupport topiaHibernateSupport) {
            Preconditions.checkNotNull(topiaHibernateSupport);
            sessionFactory = topiaHibernateSupport.getHibernateFactory();
        }

        public ConnectionProviderSupplier(Configuration configuration) {
            Properties properties = configuration.getProperties();
            StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder();
            this.standardServiceRegistry = builder.applySettings(properties).build();
        }

        @Override
        public ConnectionProvider get() {
            if (connectionProvider == null) {
                if (sessionFactory != null) {
                    // If SessionFactory is provided, use the SessionFactoryServiceRegistry
                    connectionProvider = HibernateProvider.getHibernateService(sessionFactory, ConnectionProvider.class);
                } else {
                    // otherwise use the StandardServiceRegistry
                    connectionProvider = standardServiceRegistry.getService(ConnectionProvider.class);
                }
            }
            return connectionProvider;
        }

        @Override
        public void close() throws IOException {
            // Do not close the SessionFactory, it is probably used somewhere else

            // On the over hand, if standardServiceRegistry is provided, that means the its has been created explicitly
            // for the current instance, close it
            if (standardServiceRegistry != null) {
                StandardServiceRegistryBuilder.destroy(standardServiceRegistry);
            }
        }
    }

    /**
     * Builds a new instance of Hibernate SessionFactory according to the given Hibernate Configuration
     *
     * @param hibernateConfiguration an initialized Hibernate Configuration
     * @return an instance of SessionFactory
     */
    public static SessionFactory newSessionFactory(Configuration hibernateConfiguration) {

        Properties properties = hibernateConfiguration.getProperties();

        // Use the next 2 lines if bootstrap customization is needed (classloader, autoclose, ...)
        // {@see org.hibernate.boot.registry.internal.BootstrapServiceRegistryImpl)
//            BootstrapServiceRegistry bootstrap = new BootstrapServiceRegistryBuilder().build();
//            StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder(bootstrap);

        StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder();
        StandardServiceRegistry standardServiceRegistry = builder.applySettings(properties).build();
        SessionFactory result;
        try {
            result = hibernateConfiguration.buildSessionFactory(standardServiceRegistry);
        } catch (HibernateException e) {
            SchemaValidationTopiaException.throwIfHibernateExceptionIsAboutSchemaValidation(e);
            throw e;
        }
        return result;
    }

    /**
     * Apply the given Function in a Hibernate transaction. This method will init and destroy an Hibernate
     * SessionFactory together with a single Session. This Session will be commited if no exception is raised by the
     * function, otherwise will rollback.
     *
     * @param configuration an initialized Hibernate Configuration
     * @param function      the function to run using a valid Hibernate Session
     * @param            the return type, match the function
     * @return the result of the given function
     */
    public static  V runInSession(Configuration configuration, Function function) {

        SessionFactory sessionFactory = null;
        Session session = null;
        try {
            sessionFactory = newSessionFactory(configuration);
            session = sessionFactory.openSession();

            session.getTransaction().begin();
            V result = function.apply(session);
            session.getTransaction().commit();

            return result;
        } catch (Exception eee) {
            // Exception, rollback transaction
            if (log.isErrorEnabled()) {
                log.error("Exception during Hibernate session usage, rollbacking transaction", eee);
            }
            if (session != null && session.isOpen() && TransactionStatus.ACTIVE == session.getTransaction().getStatus()) {
                session.getTransaction().rollback();
            }
            throw new TopiaException("Exception during Hibernate session usage", eee);
        } finally {
            if (session != null && session.isOpen()) {
                session.close();
            }
            if (sessionFactory != null && !sessionFactory.isClosed()) {
                sessionFactory.close();
            }
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy