Skip to content

Commit efabc6b

Browse files
committed
added "jtaTransactionManager" property to Hibernate 4 LocalSessionFactoryBean/Builder
Issue: SPR-9480
1 parent 98b281e commit efabc6b

File tree

3 files changed

+153
-4
lines changed

3 files changed

+153
-4
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2002-2012 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.orm.hibernate4;
18+
19+
import javax.transaction.TransactionManager;
20+
import javax.transaction.UserTransaction;
21+
22+
import org.hibernate.service.jta.platform.internal.AbstractJtaPlatform;
23+
24+
import org.springframework.transaction.jta.UserTransactionAdapter;
25+
import org.springframework.util.Assert;
26+
27+
/**
28+
* Implementation of Hibernate 4's {@link org.hibernate.service.jta.platform.spi.JtaPlatform}
29+
* SPI, exposing passed-in {@link TransactionManager} and {@link UserTransaction} references.
30+
*
31+
* @author Juergen Hoeller
32+
* @since 3.1.2
33+
*/
34+
class ConfigurableJtaPlatform extends AbstractJtaPlatform {
35+
36+
private final TransactionManager transactionManager;
37+
38+
private final UserTransaction userTransaction;
39+
40+
41+
/**
42+
* Create a new ConfigurableJtaPlatform instance with the given
43+
* JTA TransactionManager and optionally a given UserTransaction.
44+
* @param tm the JTA TransactionManager reference (required)
45+
* @param ut the JTA UserTransaction reference (optional)
46+
*/
47+
public ConfigurableJtaPlatform(TransactionManager tm, UserTransaction ut) {
48+
Assert.notNull(tm, "TransactionManager reference must not be null");
49+
this.transactionManager = tm;
50+
this.userTransaction = (ut != null ? ut : new UserTransactionAdapter(tm));
51+
}
52+
53+
54+
@Override
55+
protected TransactionManager locateTransactionManager() {
56+
return this.transactionManager;
57+
}
58+
59+
@Override
60+
protected UserTransaction locateUserTransaction() {
61+
return this.userTransaction;
62+
}
63+
64+
@Override
65+
protected boolean canCacheTransactionManager() {
66+
return true;
67+
}
68+
69+
@Override
70+
protected boolean canCacheUserTransaction() {
71+
return true;
72+
}
73+
74+
}

org.springframework.orm/src/main/java/org/springframework/orm/hibernate4/LocalSessionFactoryBean.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@
4848
* However, in practice, it is closer to <code>AnnotationSessionFactoryBean</code> since
4949
* its core purpose is to bootstrap a <code>SessionFactory</code> from annotation scanning.
5050
*
51+
* <p><b>NOTE:</b> To set up Hibernate 4 for Spring-driven JTA transactions, make
52+
* sure to either specify the {@link #setJtaTransactionManager "jtaTransactionManager"}
53+
* bean property or to set the "hibernate.transaction.factory_class" property to
54+
* {@link org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory}.
55+
* Otherwise, Hibernate's smart flushing mechanism won't work properly.
56+
*
5157
* @author Juergen Hoeller
5258
* @since 3.1
5359
* @see #setDataSource
@@ -82,6 +88,8 @@ public class LocalSessionFactoryBean extends HibernateExceptionTranslator
8288

8389
private String[] packagesToScan;
8490

91+
private Object jtaTransactionManager;
92+
8593
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
8694

8795
private Configuration configuration;
@@ -226,7 +234,7 @@ public Properties getHibernateProperties() {
226234

227235
/**
228236
* Specify annotated entity classes to register with this Hibernate SessionFactory.
229-
* @see org.hibernate.cfg.Configuration#addAnnotatedClass(String)
237+
* @see org.hibernate.cfg.Configuration#addAnnotatedClass(Class)
230238
*/
231239
public void setAnnotatedClasses(Class<?>[] annotatedClasses) {
232240
this.annotatedClasses = annotatedClasses;
@@ -250,6 +258,16 @@ public void setPackagesToScan(String... packagesToScan) {
250258
this.packagesToScan = packagesToScan;
251259
}
252260

261+
/**
262+
* Set the Spring {@link org.springframework.transaction.jta.JtaTransactionManager}
263+
* or the JTA {@link javax.transaction.TransactionManager} to be used with Hibernate,
264+
* if any.
265+
* @see LocalSessionFactoryBuilder#setJtaTransactionManager
266+
*/
267+
public void setJtaTransactionManager(Object jtaTransactionManager) {
268+
this.jtaTransactionManager = jtaTransactionManager;
269+
}
270+
253271
public void setResourceLoader(ResourceLoader resourceLoader) {
254272
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
255273
}
@@ -330,6 +348,10 @@ public void afterPropertiesSet() throws IOException {
330348
sfb.scanPackages(this.packagesToScan);
331349
}
332350

351+
if (this.jtaTransactionManager != null) {
352+
sfb.setJtaTransactionManager(this.jtaTransactionManager);
353+
}
354+
333355
// Build SessionFactory instance.
334356
this.configuration = sfb;
335357
this.sessionFactory = buildSessionFactory(sfb);

org.springframework.orm/src/main/java/org/springframework/orm/hibernate4/LocalSessionFactoryBuilder.java

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2011 the original author or authors.
2+
* Copyright 2002-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,12 +22,16 @@
2222
import javax.persistence.Entity;
2323
import javax.persistence.MappedSuperclass;
2424
import javax.sql.DataSource;
25+
import javax.transaction.TransactionManager;
2526

2627
import org.hibernate.HibernateException;
2728
import org.hibernate.MappingException;
2829
import org.hibernate.SessionFactory;
30+
import org.hibernate.cfg.AvailableSettings;
2931
import org.hibernate.cfg.Configuration;
3032
import org.hibernate.cfg.Environment;
33+
import org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory;
34+
import org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform;
3135

3236
import org.springframework.core.io.Resource;
3337
import org.springframework.core.io.ResourceLoader;
@@ -39,6 +43,8 @@
3943
import org.springframework.core.type.classreading.MetadataReaderFactory;
4044
import org.springframework.core.type.filter.AnnotationTypeFilter;
4145
import org.springframework.core.type.filter.TypeFilter;
46+
import org.springframework.transaction.jta.JtaTransactionManager;
47+
import org.springframework.util.Assert;
4248
import org.springframework.util.ClassUtils;
4349
import org.springframework.util.ReflectionUtils;
4450

@@ -50,6 +56,11 @@
5056
* <p>This is designed for programmatic use, e.g. in {@code @Bean} factory methods.
5157
* Consider using {@link LocalSessionFactoryBean} for XML bean definition files.
5258
*
59+
* <p><b>NOTE:</b> To set up Hibernate 4 for Spring-driven JTA transactions, make
60+
* sure to either use the {@link #setJtaTransactionManager} method or to set the
61+
* "hibernate.transaction.factory_class" property to {@link CMTTransactionFactory}.
62+
* Otherwise, Hibernate's smart flushing mechanism won't work properly.
63+
*
5364
* @author Juergen Hoeller
5465
* @since 3.1
5566
* @see LocalSessionFactoryBean
@@ -97,18 +108,60 @@ public LocalSessionFactoryBuilder(DataSource dataSource, ClassLoader classLoader
97108
* Create a new LocalSessionFactoryBuilder for the given DataSource.
98109
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
99110
* (may be <code>null</code>)
100-
* @param classLoader the ResourceLoader to load application classes from
111+
* @param resourceLoader the ResourceLoader to load application classes from
101112
*/
102113
public LocalSessionFactoryBuilder(DataSource dataSource, ResourceLoader resourceLoader) {
103114
getProperties().put(Environment.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext.class.getName());
104115
if (dataSource != null) {
105116
getProperties().put(Environment.DATASOURCE, dataSource);
106117
}
107-
getProperties().put("hibernate.classLoader.application", resourceLoader.getClassLoader());
118+
getProperties().put(AvailableSettings.APP_CLASSLOADER, resourceLoader.getClassLoader());
108119
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
109120
}
110121

111122

123+
/**
124+
* Set the Spring {@link JtaTransactionManager} or the JTA {@link TransactionManager}
125+
* to be used with Hibernate, if any. Allows for using a Spring-managed transaction
126+
* manager for Hibernate 4's session and cache synchronization, with the
127+
* "hibernate.transaction.jta.platform" automatically set to it. Also sets
128+
* "hibernate.transaction.factory_class" to {@link CMTTransactionFactory},
129+
* instructing Hibernate to interact with externally managed transactions.
130+
* <p>A passed-in Spring {@link JtaTransactionManager} needs to contain a JTA
131+
* {@link TransactionManager} reference to be usable here, except for the WebSphere
132+
* case where we'll automatically set {@link WebSphereExtendedJtaPlatform} accordingly.
133+
* <p>Note: If this is set, the Hibernate settings should not contain a JTA platform
134+
* setting to avoid meaningless double configuration.
135+
*/
136+
public LocalSessionFactoryBuilder setJtaTransactionManager(Object jtaTransactionManager) {
137+
Assert.notNull(jtaTransactionManager, "Transaction manager reference must not be null");
138+
if (jtaTransactionManager instanceof JtaTransactionManager) {
139+
boolean webspherePresent = ClassUtils.isPresent("com.ibm.wsspi.uow.UOWManager", getClass().getClassLoader());
140+
if (webspherePresent) {
141+
getProperties().put(AvailableSettings.JTA_PLATFORM, new WebSphereExtendedJtaPlatform());
142+
}
143+
else {
144+
JtaTransactionManager jtaTm = (JtaTransactionManager) jtaTransactionManager;
145+
if (jtaTm.getTransactionManager() == null) {
146+
throw new IllegalArgumentException(
147+
"Can only apply JtaTransactionManager which has a TransactionManager reference set");
148+
}
149+
getProperties().put(AvailableSettings.JTA_PLATFORM,
150+
new ConfigurableJtaPlatform(jtaTm.getTransactionManager(), jtaTm.getUserTransaction()));
151+
}
152+
}
153+
else if (jtaTransactionManager instanceof TransactionManager) {
154+
getProperties().put(AvailableSettings.JTA_PLATFORM,
155+
new ConfigurableJtaPlatform((TransactionManager) jtaTransactionManager, null));
156+
}
157+
else {
158+
throw new IllegalArgumentException(
159+
"Unknown transaction manager type: " + jtaTransactionManager.getClass().getName());
160+
}
161+
getProperties().put(AvailableSettings.TRANSACTION_STRATEGY, new CMTTransactionFactory());
162+
return this;
163+
}
164+
112165
/**
113166
* Add the given annotated classes in a batch.
114167
* @see #addAnnotatedClass

0 commit comments

Comments
 (0)