Author: athimel Date: 2012-05-14 12:10:27 +0200 (Mon, 14 May 2012) New Revision: 2475 Url: http://nuiton.org/repositories/revision/topia/2475 Log: Remove useless .hibernate. package in topia-persistence-hibernate Added: trunk/topia-persistence-hibernate/src/main/java/org/nuiton/topia/framework/TopiaHibernateConnectionProvider.java trunk/topia-persistence-hibernate/src/main/java/org/nuiton/topia/persistence/TopiaHibernatePersistenceProvider.java trunk/topia-persistence-hibernate/src/main/java/org/nuiton/topia/persistence/TopiaHibernateSpecificUtil.java Removed: trunk/topia-persistence-hibernate/src/main/java/org/nuiton/topia/framework/hibernate/ trunk/topia-persistence-hibernate/src/main/java/org/nuiton/topia/persistence/hibernate/ Modified: trunk/topia-persistence-hibernate/src/main/resources/META-INF/services/javax.persistence.spi.PersistenceProvider trunk/topia-persistence-hibernate/src/test/java/org/nuiton/topia/framework/TopiaConnectionProviderTest.java trunk/topia-persistence-hibernate/src/test/resources/TopiaContext-it.properties trunk/topia-persistence-hibernate/src/test/resources/TopiaContext-legacy.properties trunk/topia-persistence-hibernate/src/test/resources/TopiaContext-mapping.properties Copied: trunk/topia-persistence-hibernate/src/main/java/org/nuiton/topia/framework/TopiaHibernateConnectionProvider.java (from rev 2474, trunk/topia-persistence-hibernate/src/main/java/org/nuiton/topia/framework/hibernate/TopiaHibernateConnectionProvider.java) =================================================================== --- trunk/topia-persistence-hibernate/src/main/java/org/nuiton/topia/framework/TopiaHibernateConnectionProvider.java (rev 0) +++ trunk/topia-persistence-hibernate/src/main/java/org/nuiton/topia/framework/TopiaHibernateConnectionProvider.java 2012-05-14 10:10:27 UTC (rev 2475) @@ -0,0 +1,343 @@ +/* + * #%L + * ToPIA :: Persistence + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2004 - 2011 CodeLutin + * %% + * This program 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 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 Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.topia.framework; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.internal.util.ReflectHelper; +import org.hibernate.internal.util.config.ConfigurationHelper; +import org.hibernate.service.jdbc.connections.internal.ConnectionProviderInitiator; +import org.hibernate.service.jdbc.connections.spi.ConnectionProvider; +import org.hibernate.cfg.Environment; +import org.hibernate.service.spi.Configurable; +import org.hibernate.service.spi.Stoppable; + +import javax.persistence.PersistenceException; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +/** + * Customized connection provider. + * <p/> + * This provider fix the following bug : + * http://nuiton.org/issues/show/561 + * <p/> + * To use this connection provider, add this property to topia configuration + * <p/> + * <pre> + * config.setProperty(AvailableSettings.CONNECTION_PROVIDER, TopiaHibernateConnectionProvider.class.getName()); + * </pre> + * <p/> + * or in a properties file : + * <p/> + * <pre> + * hibernate.connection.provider_class=org.nuiton.topia.framework.TopiaHibernateConnectionProvider + * </pre> + * + * @author tchemit <chemit@codelutin.com> + * @since 2.5.3 + */ +public class TopiaHibernateConnectionProvider implements ConnectionProvider, Configurable, Stoppable { + + /** Logger. */ + private static final Log log = + LogFactory.getLog(TopiaHibernateConnectionProvider.class); + + /** + * JDBC url of connection. + * <p/> + * This is a mandatory hibernate configuration vi the property + * {@link Environment#URL}. + */ + private String url; + + /** All grabbed connection properties */ + private Properties connectionProps; + + /** + * Sql isolation level to use in connection. + * <p/> + * Can be configured by hibernate property {@link Environment#ISOLATION_LEVELS}. + * + * @see Connection#getTransactionIsolation() + */ + private Integer isolation; + + /** + * auto commit connection state. + * <p/> + * Can be configured by hibernate property {@link Environment#AUTOCOMMIT}. + * + * @see Connection#getAutoCommit() + */ + private boolean autocommit; + + /** + * Size of connection pool. + * <p/> + * By default use {@code 20}, can be specify by using the hibernate + * configuration property {@link Environment#POOL_SIZE}. + */ + private int poolSize; + + /** Our pool of connections which are not closed and availables. */ + private final List<Connection> pool; + + public TopiaHibernateConnectionProvider() { + pool = new ArrayList<Connection>(); + } + + @Override + public void configure(Map map) { + Map<String, String> configurationValues = (Map<String, String>)map; + + String driverClass = configurationValues.get(Environment.DRIVER); + + poolSize = ConfigurationHelper.getInt(AvailableSettings.POOL_SIZE, configurationValues, 20); // default pool size 20 + if (log.isDebugEnabled()) { + log.debug("Connection pool size: " + poolSize); + } + + autocommit = ConfigurationHelper.getBoolean( AvailableSettings.AUTOCOMMIT, configurationValues ); + if (log.isDebugEnabled()) + log.debug("autocommit mode: " + autocommit); + + isolation = ConfigurationHelper.getInteger( AvailableSettings.ISOLATION, configurationValues ); + if (isolation != null) { + if (log.isDebugEnabled()) { + log.debug("JDBC isolation level: " + + Environment.isolationLevelToString(isolation)); + } + } + + if (driverClass == null) { + + if (log.isWarnEnabled()) { + log.warn("no JDBC Driver class was specified by property " + + Environment.DRIVER); + } + } else { + try { + // trying via forName() first to be as close to DriverManager's semantics + Class.forName(driverClass); + } catch (ClassNotFoundException cnfe) { + try { + ReflectHelper.classForName(driverClass); + } catch (ClassNotFoundException e) { + String msg = "JDBC Driver class not found: " + driverClass; + log.error(msg, e); + throw new PersistenceException(msg, e); + } + } + } + + url = configurationValues.get(Environment.URL); + if (url == null) { + String msg = "JDBC URL was not specified by property " + + Environment.URL; + if (log.isErrorEnabled()) { + log.error(msg); + } + throw new PersistenceException(msg); + } + + connectionProps = + ConnectionProviderInitiator.getConnectionProperties(configurationValues); + + if (log.isDebugEnabled()) { + log.debug("using driver: " + driverClass + " at URL: " + url); + } + // if debug level is enabled, then log the password, otherwise mask it + if (log.isTraceEnabled()) { + log.debug("connection properties: " + connectionProps); + } else if (log.isDebugEnabled()) { + log.debug("connection properties: " + + ConfigurationHelper.maskOut(connectionProps, "password")); + } + } + + @Override + public Connection getConnection() throws SQLException { + + Connection connection = null; + + synchronized (pool) { + + // try to use a connection from the pool (if any) + + while (!pool.isEmpty() && connection == null) { + int last = pool.size() - 1; + if (log.isTraceEnabled()) { + log.trace("using pooled JDBC connection, pool size: " + + last); + } + + connection = pool.remove(last); + if (connection.isClosed()) { + + // this connection is closed!, don't use it + connection = null; + + if (log.isDebugEnabled()) { + log.debug("Remove already closed connection from pool " + + connection); + } + } + } + } + + if (connection == null) { + + // the pool was empty, creates a new connection + + if (log.isDebugEnabled()) { + log.debug("opening new JDBC connection to " + url); + } + connection = DriverManager.getConnection(url, connectionProps); + } + + // configure connection + + if (isolation != null) { + connection.setTransactionIsolation(isolation); + } + if (connection.getAutoCommit() != autocommit) { + connection.setAutoCommit(autocommit); + } + + return connection; + } + + @Override + public void closeConnection(Connection conn) throws SQLException { + + // if connection is already closed, nothing has to be done + // we can't keep this connection (and can not be push in pool) + + if (conn.isClosed()) { + + if (log.isDebugEnabled()) { + log.debug("Connection [" + conn + + "] alreay closed!, will not use it any longer "); + } + return; + } + + // connection was not closed, can push it in the pool (if pool is not + // full) + + synchronized (pool) { + int currentSize = pool.size(); + if (currentSize < getPoolSize()) { + if (log.isTraceEnabled()) { + log.trace("returning connection to pool, pool size: " + + (currentSize + 1)); + } + pool.add(conn); + return; + } + } + + // pool was full, must release the connection which will be loose + + if (log.isDebugEnabled()) { + log.debug("closing JDBC connection"); + } + + conn.close(); + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + stop(); + } + + @Override + public void stop() { + + if (log.isDebugEnabled()) { + log.debug("cleaning up connection pool: " + url); + } + + for (Connection connection : pool) { + try { + connection.close(); + } catch (SQLException sqle) { + if (log.isWarnEnabled()) { + log.warn("problem closing pooled connection", sqle); + } + } + } + pool.clear(); + + } + + @Override + public boolean supportsAggressiveRelease() { + return false; + } + + public String getUrl() { + return url; + } + + public Properties getConnectionProps() { + return connectionProps; + } + + public Integer getIsolation() { + return isolation; + } + + public List<Connection> getPool() { + return pool; + } + + public int getPoolSize() { + return poolSize; + } + + public boolean isAutocommit() { + return autocommit; + } + + @Override + public boolean isUnwrappableAs(Class unwrapType) { + return false; + } + + @Override + public <T> T unwrap(Class<T> unwrapType) { + return null; + } + +} Property changes on: trunk/topia-persistence-hibernate/src/main/java/org/nuiton/topia/framework/TopiaHibernateConnectionProvider.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Copied: trunk/topia-persistence-hibernate/src/main/java/org/nuiton/topia/persistence/TopiaHibernatePersistenceProvider.java (from rev 2474, trunk/topia-persistence-hibernate/src/main/java/org/nuiton/topia/persistence/hibernate/TopiaHibernatePersistenceProvider.java) =================================================================== --- trunk/topia-persistence-hibernate/src/main/java/org/nuiton/topia/persistence/TopiaHibernatePersistenceProvider.java (rev 0) +++ trunk/topia-persistence-hibernate/src/main/java/org/nuiton/topia/persistence/TopiaHibernatePersistenceProvider.java 2012-05-14 10:10:27 UTC (rev 2475) @@ -0,0 +1,115 @@ +package org.nuiton.topia.persistence; + +import com.google.common.base.Function; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import org.apache.commons.lang3.tuple.Pair; +import org.hibernate.cfg.Configuration; +import org.hibernate.ejb.Ejb3Configuration; +import org.hibernate.ejb.packaging.NamedInputStream; +import org.hibernate.ejb.packaging.PersistenceMetadata; +import org.nuiton.topia.framework.TopiaPersistenceProvider; +import org.nuiton.topia.framework.TopiaSpecificUtil; + +import javax.persistence.EntityManagerFactory; +import java.io.InputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Hibernate implementation of the TopiaPersistenceProvider + * + * @author Arnaud Thimel <thimel@codelutin.com> + */ +public class TopiaHibernatePersistenceProvider extends TopiaPersistenceProvider { + + public static final Function<Class<?>, String> GET_FQN = new Function<Class<?>, String>() { + @Override + public String apply(Class<?> entityClass) { + return entityClass.getName(); + } + }; + + public static final Function<String, String> GET_ENTITY_NAME_SLASHED = new Function<String, String>() { + @Override + public String apply(String entityClassName) { + String result = entityClassName.replaceAll("[.]", "/"); + return result; + } + }; + public static final Function<String, NamedInputStream> GET_HBM_NAMED_INPUT_STREAM = new Function<String, NamedInputStream>() { + @Override + public NamedInputStream apply(String entityClassName) { + // Get the path of the .hbm.xml file + String entityNameSlashed = GET_ENTITY_NAME_SLASHED.apply(entityClassName); + String entityHbmPath = "/" + entityNameSlashed + ".hbm.xml"; + InputStream entityHbmIS = TopiaPersistenceProvider.class.getResourceAsStream(entityHbmPath); + NamedInputStream entityHbmNIS = new NamedInputStream(entityClassName, entityHbmIS); + return entityHbmNIS; + } + }; + + public static final Function<String, String> GET_ORM_FILE_PATH = new Function<String, String>() { + @Override + public String apply(String entityClassName) { + // Get the path of the -orm.xml file + String entityNameSlashed = GET_ENTITY_NAME_SLASHED.apply(entityClassName); + String entityMappingPath = entityNameSlashed + "-orm.xml"; + return entityMappingPath; + } + }; + + @Override + public Pair<EntityManagerFactory, TopiaSpecificUtil> configureSpecific(String entityManagerName, Map<String, Object> properties, Set<Class<?>> entities) { + + Map<String, Object> hibernateProperties = new HashMap<String, Object>(properties); + // Convert everything from topia.connection.* to hibernate.connection.* + for (String key : properties.keySet()) { + if (key.startsWith("topia.connection.")) { + Object value = properties.get(key); + String hibernateKey = "hibernate." + key.substring(6); + hibernateProperties.put(hibernateKey, value); + } + } + + // For each entity, get its FQN + List<String> entitiesNames = Lists.newArrayList( + Iterables.transform(entities, GET_FQN)); + + // For each entity, get the HBM InputStream + List<NamedInputStream> entitiesHbmFiles = Lists.newArrayList( + Iterables.transform(entitiesNames, GET_HBM_NAMED_INPUT_STREAM)); + + // For each entity, get the ORM mapping path + List<String> entitiesMappingFiles = Lists.newArrayList( + Iterables.transform(entitiesNames, GET_ORM_FILE_PATH)); + + // This is deprecated but still the way it done inside Hibernate itself + Ejb3Configuration cfg = new Ejb3Configuration(); + PersistenceMetadata metadata = new PersistenceMetadata(); + metadata.setName(entityManagerName); + + // Register the entities, hbm and mappings + metadata.setClasses(entitiesNames); + metadata.setHbmfiles(entitiesHbmFiles); // HBM files +// metadata.setMappingFiles(entitiesMappingFiles); // ORM files + + // Start configuration and build EntityManagerFactory + Ejb3Configuration configured = cfg.configure(metadata, hibernateProperties); + EntityManagerFactory entityManagerFactory = null; + if (configured != null) { + entityManagerFactory = configured.buildEntityManagerFactory(); + } + + Configuration hibernateConfiguration = configured.getHibernateConfiguration(); + TopiaSpecificUtil specificUtil = + new TopiaHibernateSpecificUtil(hibernateConfiguration); + + Pair<EntityManagerFactory, TopiaSpecificUtil> result = + Pair.of(entityManagerFactory, specificUtil); + return result; + } + +} Copied: trunk/topia-persistence-hibernate/src/main/java/org/nuiton/topia/persistence/TopiaHibernateSpecificUtil.java (from rev 2474, trunk/topia-persistence-hibernate/src/main/java/org/nuiton/topia/persistence/hibernate/TopiaHibernateSpecificUtil.java) =================================================================== --- trunk/topia-persistence-hibernate/src/main/java/org/nuiton/topia/persistence/TopiaHibernateSpecificUtil.java (rev 0) +++ trunk/topia-persistence-hibernate/src/main/java/org/nuiton/topia/persistence/TopiaHibernateSpecificUtil.java 2012-05-14 10:10:27 UTC (rev 2475) @@ -0,0 +1,114 @@ +package org.nuiton.topia.persistence; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Configuration; +import org.hibernate.dialect.Dialect; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Table; +import org.hibernate.tool.hbm2ddl.DatabaseMetadata; +import org.hibernate.tool.hbm2ddl.SchemaExport; +import org.hibernate.tool.hbm2ddl.SchemaUpdate; +import org.hibernate.tool.hbm2ddl.TableMetadata; +import org.nuiton.topia.framework.TopiaSpecificUtil; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Iterator; + +/** + * @author Arnaud Thimel <thimel@codelutin.com> + */ +public class TopiaHibernateSpecificUtil implements TopiaSpecificUtil { + + private static final Log log = LogFactory.getLog(TopiaHibernateSpecificUtil.class); + + protected Configuration configuration; + + public TopiaHibernateSpecificUtil(Configuration configuration) { + this.configuration = configuration; + } + + @Override + public void createSchema(boolean showSchema) { + SchemaExport schemaExport = new SchemaExport(configuration); + schemaExport.create(showSchema, true); + } + + @Override + public void showCreateSchema() { + new SchemaExport(configuration).execute(true, false, false, true); + } + + @Override + public void updateSchema(boolean showSchema) { + new SchemaUpdate(configuration).execute(showSchema, true); + } + + @Override + public boolean isSchemaExist(Class<?> clazz) { + String entityName = clazz.getName(); + + boolean result = false; + try { + PersistentClass classMapping = + configuration.getClassMapping(entityName); + if (classMapping == null) { + if (log.isInfoEnabled()) { + Iterator<?> itr = configuration.getClassMappings(); + while (itr.hasNext()) { + log.info("available mapping " + itr.next()); + } + } + 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 = +// ConnectionProviderFactory.newConnectionProvider( +// configuration.getProperties()); + + Dialect dialect = Dialect.getDialect(configuration.getProperties()); + + Connection connection = null; + try { +// connection = connectionProvider.getConnection(); + + // FIXME AThimel 10/05/2012 It would be better to re-use the ConnectionProvider but I can't find how to do it for the moment + String url = configuration.getProperty(AvailableSettings.URL); + String username = configuration.getProperty(AvailableSettings.USER); + String password = configuration.getProperty(AvailableSettings.PASS); + connection = DriverManager.getConnection(url, username, password); + + DatabaseMetadata meta = new DatabaseMetadata(connection, dialect); + + TableMetadata tmd = meta.getTableMetadata( + testTable.getName(), testTable.getSchema(), + testTable.getCatalog(), testTable.isQuoted()); + + if (tmd != null) { + //table exist + result = true; + } + } finally { + if (connection != null) { + connection.close(); + } + } + + } catch (SQLException e) { + log.error("Cant connect to database", e); +// } catch (TopiaNotFoundException e) { +// log.error("Cant connect to database", e); + } + + return result; + } +} Modified: trunk/topia-persistence-hibernate/src/main/resources/META-INF/services/javax.persistence.spi.PersistenceProvider =================================================================== --- trunk/topia-persistence-hibernate/src/main/resources/META-INF/services/javax.persistence.spi.PersistenceProvider 2012-05-14 09:58:22 UTC (rev 2474) +++ trunk/topia-persistence-hibernate/src/main/resources/META-INF/services/javax.persistence.spi.PersistenceProvider 2012-05-14 10:10:27 UTC (rev 2475) @@ -1 +1 @@ -org.nuiton.topia.persistence.hibernate.TopiaHibernatePersistenceProvider +org.nuiton.topia.persistence.TopiaHibernatePersistenceProvider \ No newline at end of file Modified: trunk/topia-persistence-hibernate/src/test/java/org/nuiton/topia/framework/TopiaConnectionProviderTest.java =================================================================== --- trunk/topia-persistence-hibernate/src/test/java/org/nuiton/topia/framework/TopiaConnectionProviderTest.java 2012-05-14 09:58:22 UTC (rev 2474) +++ trunk/topia-persistence-hibernate/src/test/java/org/nuiton/topia/framework/TopiaConnectionProviderTest.java 2012-05-14 10:10:27 UTC (rev 2475) @@ -46,7 +46,7 @@ import static org.junit.Assert.assertNotNull; /** - * To test the {@link org.nuiton.topia.framework.hibernate.TopiaHibernateConnectionProvider} and make sure all connections + * To test the {@link TopiaHibernateConnectionProvider} and make sure all connections * are done from here... * * @author tchemit <chemit@codelutin.com> Modified: trunk/topia-persistence-hibernate/src/test/resources/TopiaContext-it.properties =================================================================== --- trunk/topia-persistence-hibernate/src/test/resources/TopiaContext-it.properties 2012-05-14 09:58:22 UTC (rev 2474) +++ trunk/topia-persistence-hibernate/src/test/resources/TopiaContext-it.properties 2012-05-14 10:10:27 UTC (rev 2475) @@ -9,4 +9,4 @@ topia.connection.driver_class=org.h2.Driver #Not necessary, but useful -hibernate.connection.provider_class=org.nuiton.topia.framework.hibernate.TopiaHibernateConnectionProvider +hibernate.connection.provider_class=org.nuiton.topia.framework.TopiaHibernateConnectionProvider Modified: trunk/topia-persistence-hibernate/src/test/resources/TopiaContext-legacy.properties =================================================================== --- trunk/topia-persistence-hibernate/src/test/resources/TopiaContext-legacy.properties 2012-05-14 09:58:22 UTC (rev 2474) +++ trunk/topia-persistence-hibernate/src/test/resources/TopiaContext-legacy.properties 2012-05-14 10:10:27 UTC (rev 2475) @@ -9,4 +9,4 @@ topia.connection.driver_class=org.h2.Driver #Not necessary, but useful -hibernate.connection.provider_class=org.nuiton.topia.framework.hibernate.TopiaHibernateConnectionProvider +hibernate.connection.provider_class=org.nuiton.topia.framework.TopiaHibernateConnectionProvider Modified: trunk/topia-persistence-hibernate/src/test/resources/TopiaContext-mapping.properties =================================================================== --- trunk/topia-persistence-hibernate/src/test/resources/TopiaContext-mapping.properties 2012-05-14 09:58:22 UTC (rev 2474) +++ trunk/topia-persistence-hibernate/src/test/resources/TopiaContext-mapping.properties 2012-05-14 10:10:27 UTC (rev 2475) @@ -9,4 +9,4 @@ topia.connection.driver_class=org.h2.Driver #Not necessary, but useful -hibernate.connection.provider_class=org.nuiton.topia.framework.hibernate.TopiaHibernateConnectionProvider +hibernate.connection.provider_class=org.nuiton.topia.framework.TopiaHibernateConnectionProvider