Hibernate 4 MultiTenancy Spring 3 Schema Export Error - spring

I'm trying to configure a Hibernate SessionFactory using multi-tenancy options and with automatic schema creation, however i'm stuck on this error:
java.lang.NullPointerException
at org.hibernate.tool.hbm2ddl.SuppliedConnectionProviderConnectionHelper.prepare(SuppliedConnectionProviderConnectionHelper.java:51)
at org.hibernate.tool.hbm2ddl.DatabaseExporter.<init>(DatabaseExporter.java:52)
at org.hibernate.tool.hbm2ddl.SchemaExport.execute(SchemaExport.java:367)
at org.hibernate.tool.hbm2ddl.SchemaExport.create(SchemaExport.java:304)
at org.hibernate.tool.hbm2ddl.SchemaExport.create(SchemaExport.java:293)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:498)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1742)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1780)
at org.springframework.orm.hibernate4.LocalSessionFactoryBuilder.buildSessionFactory(LocalSessionFactoryBuilder.java:242)
Here is my spring configuration:
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource1"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</prop>
<prop key="hibernate.multiTenancy">DATABASE</prop>
<prop key="hibernate.multi_tenant_connection_provider">org.springframework.webflow.samples.booking.SampleMultiTenantConnectionProvider</prop>
<prop key="hibernate.tenant_identifier_resolver">org.springframework.webflow.samples.booking.SampleCurrentTenantIdentifierResolver</prop>
</props>
</property>
</bean>
<!-- Deploys a in-memory "booking" datasource populated -->
<bean id="dataSource1" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:booking1" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="dataSource2" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:booking2" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
For now i'm using only DataSource 1, and the SampleConnectionProvider and TenantResolver always return the same tenant and datasource. However when Schema Export runs, it throws NullPointerException. The supplied ConnectionProvider to the SuppliedConnectionProviderHelper is null. It appears that he can't choose an appropriate ConnectionProvider when using multitenancy. The SuppliedConnectionProviderHelper is created on SchemaExport:
this.connectionHelper = new SuppliedConnectionProviderConnectionHelper(
serviceRegistry.getService( ConnectionProvider.class )
);
Can you use the hibernate.hbm2ddl.auto when using multitenancy? Already search in hibernate documentation but did not find anything.
Any help would be much appreciated!
Best regards
João Simas

It looks like there is no support for multi-tenancy in SchemaExport. I looked at source code in other places connection provider is obtained based on multi-tenancy strategy. See line 581 here. I don't see that happen in SchemaExport. Also if there are multiple data sources, SchemaExport should automatically create schema in other data sources as well. I don't see SchemaExport do anything like that.
See and JIRA issue . The JIRA issue does not have exact problem you described but there is work around suggested for creating schema in comments.
This is just my static analysis. You should probably open issue or wait here for someone to post answer. As far as I know, this seems to be bug or unsupported feature.

This is a bug in Hibernate...
https://hibernate.atlassian.net/browse/HHH-7395

Related

Hibernate Envers not Finding JPA Transaction:

I've been trying to wrap my head around this issue all day.
Currently our project has setup JPATransactionManager through a Spring Application Context to take care of our various session transactions with the use of #Transactional on all services that take care of persistence and deletions (DAO usage).
Changing over from Hibernate 3 to 5, we wanted to remove our use of a custom audit interceptor and move onto using Hibernate Envers. I have annotated all my classes properly and have the tables being created, but once it actually gets to a point of insertion, the listener throws an error in which it can't find the current transaction given by JPA:
org.hibernate.envers.exception.AuditException: Unable to create revision because of non-active transaction
at org.hibernate.envers.event.spi.BaseEnversEventListener.checkIfTransactionInProgress(BaseEnversEventListener.java:132)
at org.hibernate.envers.event.spi.EnversPostInsertEventListenerImpl.onPostInsert(EnversPostInsertEventListenerImpl.java:34)
at org.hibernate.action.internal.EntityIdentityInsertAction.postInsert(EntityIdentityInsertAction.java:156)
at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:102)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:597)
at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:232)
at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:213)
at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:256)
at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:318)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:275)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:182)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:113)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:97)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:651)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:643)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:638)
Looking inside the code, it seems that it's basing the transaction status off it's default value of INACTIVE meaning that it's not hooking into the transaction properly. I know that Hibernate Envers also automatically pushes the listeners into hibernate with recent versions so I don't know if this may also be a source of the issue.
I know that its been documented to work with HibernateTransactionManager but we wish to step away from using that in favor of hooking up our transactions and sessions solely via Spring making things easier so it may also be the need of finding an alternative to envers. Does anyone have any advice or solutions to this problem? Or also hit this issue?
ApplicationContext.xml
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="dataSource" ref=“dataSource" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="net.sourceforge.jtds.jdbcx.JtdsDataSource" />
<property name="url" value="jdbc:jtds:sqlserver://.." />
<property name="username" value=“..." />
<property name="password" value=“..." />
</bean>
<bean id="hibernateProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location">
<value>classpath:hibernate.properties</value>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="hibernateProperties">
<ref bean="hibernateProperties" />
</property>
</bean>
<bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="find*">PROPAGATION_SUPPORTS,readOnly
</prop>
<prop key="load*">PROPAGATION_SUPPORTS,readOnly
</prop>
<prop key="make*">PROPAGATION_REQUIRED</prop>
<prop key="add*">PROPAGATION_REQUIRED</prop>
<prop key="refresh">PROPAGATION_SUPPORTS</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly
</prop>
</props>
</property>
</bean>
<bean id="PROPAGATION_REQUIRED" class="org.apache.camel.spring.spi.SpringTransactionPolicy">
<property name="transactionManager" ref="transactionManager" />
</bean>
hibernate.properties
#hibernate.hbm2ddl.auto=update
hibernate.show_sql=true
hibernate.connection.datasource=java\:comp/env/datasource
#hibernate.connection.provider_class=org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl
hibernate.connection.provider_class=org.hibernate.connection.DatasourceConnectionProvider
hibernate.cache.use_second_level_cache=true
hibernate.cache.use_query_cache=true
#hibernate.generate_statistics=true
hibernate.cache.use_structured_entries=true
hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
hibernate.id.new_generator_mappings=false
hibernate.dialect=org.hibernate.dialect.SQLServer2008Dialect
hibernate.listeners.envers.autoRegister=false
org.hibernate.envers.track_entities_changed_in_revision=false
org.hibernate.envers.audit_table_prefix=AUD_
org.hibernate.envers.audit_table_suffix=
My DAOs are hooked up using the txProxyTemplate like so
<bean id="objectDAO" parent="txProxyTemplate">
<property name="target">
<bean
class="path.to.objectDAOImpl">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
</property>
</bean>
All my services that use the various DAOs are simply hooked up using the #Transactional annotation where we want to have transactions. I've been able to see through trace that my transactions are succeeding in completing and rolling back as well when there are errors. Once I added envers into the mix, the auditing can't find the transaction to join. There must be something I'm missing but I'm not sure what it is.
I don't believe you need to define a txProxyTemplate bean nor a SpringTransactionPolicy from my experience. This functionality has since been superseded with the <tx:/> tags and the use of the #Transactional annotation.
You just need to make sure a JpaTransactionManager has been created and associated as the transactionManager associated with the <tx:annotation-driven/> tag.

Spring MVC refresh database beans in application context

I am developping a Spring MVC web application that use the dbcp database connection pool.
<bean id="datasourceAR_XXX" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" scope="singleton">
<property name="driverClassName"><value>oracle.jdbc.driver.OracleDriver</value></property>
<property name="url"><value>jdbc:oracle:thin:#XXX.XXX.com:1500:SERVICE</value></property>
<property name="maxActive"><value>100</value></property>
<property name="maxIdle"><value>10</value></property>
<property name="username"><value>XXX</value></property>
<property name="password"><value>XXX</value></property>
</bean>
I recently moved the scope of those beans to singleton because the amount of connection per session started to be a bit too much.
The problem is :
Our database is shutting down every sunday and the spring application seems to act strangely by keeping the socket open and does not refresh the connection as I thought it would do.
Is there a way to refresh the beans scoped as singleton in a way that will refresh the connection everyday and not be obliged to relaunch the application every monday?
What you want to do is to configure validation for your connections. When a connection is borrowed from the pool you want to make sure that that connection is valid. For this you can specify the validationQuery property on your datasource.
<bean id="datasourceAR_XXX" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" scope="singleton">
<property name="driverClassName"><value>oracle.jdbc.driver.OracleDriver</value></property>
<property name="url"><value>jdbc:oracle:thin:#XXX.XXX.com:1500:SERVICE</value></property>
<property name="maxActive"><value>100</value></property>
<property name="maxIdle"><value>10</value></property>
<property name="username"><value>XXX</value></property>
<property name="password"><value>XXX</value></property>
<property name="validationQuery" value="select 1 from dual" />
</bean>
See DBCP - validationQuery for different Databases for a list of possible validation queries for different databases.
There are some issues with Commons DBCP and it is pretty old (although there is a DBCP 2.x now). I would suggest moving to a different datasource like HikariCP this datasource is also a JDBC 4.x based datasource which allows for easier connection validation (it is part of the JDBC 4 spec).
<bean id="datasourceAR_XXX" class="com.zaxxer.hikari.HikariDataSource">
<property name="datasourceClassName" value="oracle.jdbc.pool.OracleDataSource"/>
<property name="maximumPoolSize" value="20" />
<property name="username" value="XXX" />
<property name="password" value="XXX" />
<property name="datasourceProperties">
<props>
<prop key="serverName">XXX.XXX.com</prop>
<prop key="port">1500</prop>
<prop key="databaseName">SERVICE</prop>
</props>
</property>
</bean>
If your oracle driver is new enough you don't need a validation query anymore as validation is provided by the driver instead of needing to be done with a query. Next to that you probably have better results with this pool.
Also you might have a bit of a large pool size, nice article/presentation about pool sizing can be found here.

org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter generateDdl Not Working

I'm using Spring 3.* using JPA hibernate impl and I've set the Spring org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter generateDdl to true, but I don't see it actually doing anything. I swap it to false and I get the same output in my log. Anyone know what this setting is supposed to do? Its not generating the ddl.
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="api" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaProperties">
<props>
<prop key="hibernate.use_sql_comments">${jpa.vendor.showsql}</prop>
<prop key="hibernate.generate_statistics">${jpa.vendor.generate.statistics}</prop>
<prop key="hibernate.archive.autodetection">class</prop>
<prop key="hibernate.cache.use_second_level_cache">${cache.use.secondLevel}</prop>
<prop key="hibernate.cache.use_query_cache">${cache.use.query}</prop>
</props>
</property>
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="${console.show.sql}" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
</bean>
If you use an IDE that has good Spring/XML support (notably IntelliJ IDEA), you can view what each property should do (in IDEA put the cursor on it and press CTRL+Q). The specc says:
Set whether to generate DDL after the EntityManagerFactory has been
initialized, creating/updating all relevant tables. Note that the
exact semantics of this flag depend on the underlying persistence
provider. For any more advanced needs, specify the appropriate
vendor-specific settings as "jpaProperties".
Having the value true means that if the database tables don't exist or need to be updated, it will be done automatically. If the value is false, you will have to do it manually.

Spring multiple transaction managers, single transaction

I have a complex situation where I have to use 2 different databases, there for I use 2 different transaction managers. Is there a way in Spring to link these transaction managers to work in a single transaction ? In case of an exception on the second dataSource changes on the first should be rolled-back.
<bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="remove*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#dummyHost:1521:dummySID" />
<property name="username" value="owner" />
<property name="password" value="password" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#dummyHost2:1521:dummySID2" />
<property name="username" value="owner" />
<property name="password" value="password" />
</bean>
<bean id="transactionManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource2" />
</bean>
You can use Spring's JtaTransactionManager to make sure both DBs are transacted with a single transaction manager.
Note, you would have to choose an underlying implementation which can either be a container's one: e.g. WebLogic, WebSphere and OC4J, etc.. or a stand alone, even an open source one: e.g. Atomikos.
HOWEVER
XA transaction management complicates things (configuration / performance / problem resolution / maintenance / etc.). And in a lot of cases, it can be avoided by clever patterns.
To get a solid understanding on whether you need to use XA ( e.g. distributed ) transaction manager, take a look at this fantastic article by Spring's own Dave Syer: Distributed transactions in Spring, with and without XA
You need a global transaction manager which supports 2-phase-commit (XA). Several independent and free ones are available. I've used Bitronix in a Spring-based project, but there is also Atomikos, and probably others. See http://en.wikipedia.org/wiki/Java_Transaction_API#Opensource_JTA_implementations
For routing through multiple datasource, You could use abstractRoutingDataSource but if you have requirements like one rollbackack affecting another you would need a JtaTransactionManager for distributed txn management .

Unable to use macros with velocity in email templates?

greetings all
i am using velocity templates when sending emails
and i want to read texts dynamically from property files depending on user locale
the xml config:
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:messages</value>
<value>classpath:messages_ar</value>
</list>
</property>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
<bean id="velocityEngine"
class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
<property name="velocityProperties">
<props>
<prop key="resource.loader">class</prop>
<prop key="class.resource.loader.class">org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader</prop>
<prop key="velocimacro.library">org/springframework/web/servlet/view/velocity/spring.vm</prop>
</props>
</property>
</bean>
<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<property name="resourceLoaderPath" value="/WEB-INF/classes/com/spacerdv/mailTemplates"/>
</bean>
<!--
View resolvers can also be configured with ResourceBundles or XML files. If you need
different view resolving based on Locale, you have to use the resource bundle resolver.
-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="cache" value="true"/>
<property name="prefix" value=""/>
<property name="suffix" value=".vm"/>
<!-- if you want to use the Spring Velocity macros, set this property to true -->
<property name="exposeSpringMacroHelpers" value="true"/>
</bean>
and when trying to read the text from property file like :
<span>#springMessage("hi.message")</span>
it doesn't read any thing, or prints the default value, just prints:
$springMacroRequestContext.getMessage($code)
i don't know why? , am i missing something ?, any help ?
When using the velocity engine for sending emails, you may have to configure your engine tu use the velocimacro librabry shipped within spring.
<bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
<property name="velocityProperties">
<props>
<prop key="resource.loader">class</prop>
<prop key="class.resource.loader.class">org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader</prop>
<prop key="velocimacro.library">org/springframework/web/servlet/view/velocity/spring.vm</prop>
</props>
</property>
</bean>
You can check the example in spring documentation.
If Spring doesn't inject automatically the $springMacroRequestContext variable into your model, you should put it yourself:
model.put("springMacroRequestContext", new RequestContext(request, response, getServletContext(), model));
That's basically what they do in the AbstractTemplateView class. I guess you won't be able to do it, since you're handling emails here, and not web requests. But that's definitely a hint on what you can do to get it working.
macros can't be used outside web app like in email templates, so a solution would be to pass messageSource to the vm file and read from the property file by it like the answer in here:
Is it possible to read static text dynamically from property files in velocity template?

Resources