
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