Upgrade to JPA 2.1+ and Bean Validation 1.1+; remove native support for Hibernate 3.6 and 4.x
Issue: SPR-13481 Issue: SPR-13827
This commit is contained in:
parent
69ec437fbc
commit
54004e0d78
|
|
@ -24,11 +24,13 @@ import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import javax.validation.Configuration;
|
import javax.validation.Configuration;
|
||||||
import javax.validation.ConstraintValidatorFactory;
|
import javax.validation.ConstraintValidatorFactory;
|
||||||
import javax.validation.MessageInterpolator;
|
import javax.validation.MessageInterpolator;
|
||||||
|
import javax.validation.ParameterNameProvider;
|
||||||
import javax.validation.TraversableResolver;
|
import javax.validation.TraversableResolver;
|
||||||
import javax.validation.Validation;
|
import javax.validation.Validation;
|
||||||
import javax.validation.ValidationProviderResolver;
|
import javax.validation.ValidationProviderResolver;
|
||||||
|
|
@ -66,14 +68,8 @@ import org.springframework.util.ReflectionUtils;
|
||||||
* you will almost always use the default Validator anyway. This can also be injected directly
|
* you will almost always use the default Validator anyway. This can also be injected directly
|
||||||
* into any target dependency of type {@link org.springframework.validation.Validator}!
|
* into any target dependency of type {@link org.springframework.validation.Validator}!
|
||||||
*
|
*
|
||||||
* <p><b>As of Spring 4.0, this class supports Bean Validation 1.0 and 1.1, with special support
|
* <p><b>As of Spring 5.0, this class requires Bean Validation 1.1, with special support
|
||||||
* for Hibernate Validator 4.3 and 5.x</b> (see {@link #setValidationMessageSource}).
|
* for Hibernate Validator 5.x</b> (see {@link #setValidationMessageSource}).
|
||||||
*
|
|
||||||
* <p>Note that Bean Validation 1.1's {@code #forExecutables} method isn't supported: We do not
|
|
||||||
* expect that method to be called by application code; consider {@link MethodValidationInterceptor}
|
|
||||||
* instead. If you really need programmatic {@code #forExecutables} access, inject this class as
|
|
||||||
* a {@link ValidatorFactory} and call {@link #getValidator()} on it, then {@code #forExecutables}
|
|
||||||
* on the returned native {@link Validator} reference instead of directly on this class.
|
|
||||||
*
|
*
|
||||||
* <p>This class is also being used by Spring's MVC configuration namespace, in case of the
|
* <p>This class is also being used by Spring's MVC configuration namespace, in case of the
|
||||||
* {@code javax.validation} API being present but no explicit Validator having been configured.
|
* {@code javax.validation} API being present but no explicit Validator having been configured.
|
||||||
|
|
@ -88,10 +84,6 @@ import org.springframework.util.ReflectionUtils;
|
||||||
public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||||
implements ValidatorFactory, ApplicationContextAware, InitializingBean, DisposableBean {
|
implements ValidatorFactory, ApplicationContextAware, InitializingBean, DisposableBean {
|
||||||
|
|
||||||
// Bean Validation 1.1 close() method available?
|
|
||||||
private static final Method closeMethod = ClassUtils.getMethodIfAvailable(ValidatorFactory.class, "close");
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
private Class providerClass;
|
private Class providerClass;
|
||||||
|
|
||||||
|
|
@ -305,55 +297,23 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
private void configureParameterNameProviderIfPossible(Configuration<?> configuration) {
|
private void configureParameterNameProviderIfPossible(Configuration<?> configuration) {
|
||||||
try {
|
// TODO: inner class
|
||||||
Class<?> parameterNameProviderClass =
|
final ParameterNameDiscoverer discoverer = this.parameterNameDiscoverer;
|
||||||
ClassUtils.forName("javax.validation.ParameterNameProvider", getClass().getClassLoader());
|
final ParameterNameProvider defaultProvider = configuration.getDefaultParameterNameProvider();
|
||||||
Method parameterNameProviderMethod =
|
configuration.parameterNameProvider(new ParameterNameProvider() {
|
||||||
Configuration.class.getMethod("parameterNameProvider", parameterNameProviderClass);
|
@Override
|
||||||
final Object defaultProvider = ReflectionUtils.invokeMethod(
|
public List<String> getParameterNames(Constructor<?> constructor) {
|
||||||
Configuration.class.getMethod("getDefaultParameterNameProvider"), configuration);
|
String[] paramNames = discoverer.getParameterNames(constructor);
|
||||||
final ParameterNameDiscoverer discoverer = this.parameterNameDiscoverer;
|
return (paramNames != null ? Arrays.asList(paramNames) :
|
||||||
Object parameterNameProvider = Proxy.newProxyInstance(getClass().getClassLoader(),
|
defaultProvider.getParameterNames(constructor));
|
||||||
new Class<?>[] {parameterNameProviderClass}, new InvocationHandler() {
|
}
|
||||||
@Override
|
@Override
|
||||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
public List<String> getParameterNames(Method method) {
|
||||||
if (method.getName().equals("getParameterNames")) {
|
String[] paramNames = discoverer.getParameterNames(method);
|
||||||
String[] result = null;
|
return (paramNames != null ? Arrays.asList(paramNames) :
|
||||||
if (args[0] instanceof Constructor) {
|
defaultProvider.getParameterNames(method));
|
||||||
result = discoverer.getParameterNames((Constructor<?>) args[0]);
|
}
|
||||||
}
|
});
|
||||||
else if (args[0] instanceof Method) {
|
|
||||||
result = discoverer.getParameterNames((Method) args[0]);
|
|
||||||
}
|
|
||||||
if (result != null) {
|
|
||||||
return Arrays.asList(result);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
try {
|
|
||||||
return method.invoke(defaultProvider, args);
|
|
||||||
}
|
|
||||||
catch (InvocationTargetException ex) {
|
|
||||||
throw ex.getTargetException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// toString, equals, hashCode
|
|
||||||
try {
|
|
||||||
return method.invoke(this, args);
|
|
||||||
}
|
|
||||||
catch (InvocationTargetException ex) {
|
|
||||||
throw ex.getTargetException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ReflectionUtils.invokeMethod(parameterNameProviderMethod, configuration, parameterNameProvider);
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
// Bean Validation 1.1 API not available - simply not applying the ParameterNameDiscoverer
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -397,9 +357,14 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||||
return this.validatorFactory.getConstraintValidatorFactory();
|
return this.validatorFactory.getConstraintValidatorFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ParameterNameProvider getParameterNameProvider() {
|
||||||
|
return this.validatorFactory.getParameterNameProvider();
|
||||||
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
if (closeMethod != null && this.validatorFactory != null) {
|
if (this.validatorFactory != null) {
|
||||||
ReflectionUtils.invokeMethod(closeMethod, this.validatorFactory);
|
this.validatorFactory.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -26,7 +26,6 @@ import javax.validation.ValidatorFactory;
|
||||||
|
|
||||||
import org.aopalliance.intercept.MethodInterceptor;
|
import org.aopalliance.intercept.MethodInterceptor;
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
import org.hibernate.validator.HibernateValidator;
|
|
||||||
|
|
||||||
import org.springframework.core.BridgeMethodResolver;
|
import org.springframework.core.BridgeMethodResolver;
|
||||||
import org.springframework.core.annotation.AnnotationUtils;
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
|
|
@ -48,9 +47,8 @@ import org.springframework.validation.annotation.Validated;
|
||||||
* at the type level of the containing target class, applying to all public service methods
|
* at the type level of the containing target class, applying to all public service methods
|
||||||
* of that class. By default, JSR-303 will validate against its default group only.
|
* of that class. By default, JSR-303 will validate against its default group only.
|
||||||
*
|
*
|
||||||
* <p>As of Spring 4.0, this functionality requires either a Bean Validation 1.1 provider
|
* <p>As of Spring 5.0, this functionality requires a Bean Validation 1.1 provider
|
||||||
* (such as Hibernate Validator 5.x) or the Bean Validation 1.0 API with Hibernate Validator
|
* (such as Hibernate Validator 5.x).
|
||||||
* 4.3. The actual provider will be autodetected and automatically adapted.
|
|
||||||
*
|
*
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @since 3.1
|
* @since 3.1
|
||||||
|
|
@ -88,8 +86,7 @@ public class MethodValidationInterceptor implements MethodInterceptor {
|
||||||
* Create a new MethodValidationInterceptor using a default JSR-303 validator underneath.
|
* Create a new MethodValidationInterceptor using a default JSR-303 validator underneath.
|
||||||
*/
|
*/
|
||||||
public MethodValidationInterceptor() {
|
public MethodValidationInterceptor() {
|
||||||
this(forExecutablesMethod != null ? Validation.buildDefaultValidatorFactory() :
|
this(Validation.buildDefaultValidatorFactory());
|
||||||
HibernateValidatorDelegate.buildValidatorFactory());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -114,43 +111,36 @@ public class MethodValidationInterceptor implements MethodInterceptor {
|
||||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||||
Class<?>[] groups = determineValidationGroups(invocation);
|
Class<?>[] groups = determineValidationGroups(invocation);
|
||||||
|
|
||||||
if (forExecutablesMethod != null) {
|
// Standard Bean Validation 1.1 API
|
||||||
// Standard Bean Validation 1.1 API
|
Object execVal = ReflectionUtils.invokeMethod(forExecutablesMethod, this.validator);
|
||||||
Object execVal = ReflectionUtils.invokeMethod(forExecutablesMethod, this.validator);
|
Method methodToValidate = invocation.getMethod();
|
||||||
Method methodToValidate = invocation.getMethod();
|
Set<ConstraintViolation<?>> result;
|
||||||
Set<ConstraintViolation<?>> result;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateParametersMethod,
|
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateParametersMethod,
|
||||||
execVal, invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
|
execVal, invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException ex) {
|
catch (IllegalArgumentException ex) {
|
||||||
// Probably a generic type mismatch between interface and impl as reported in SPR-12237 / HV-1011
|
// Probably a generic type mismatch between interface and impl as reported in SPR-12237 / HV-1011
|
||||||
// Let's try to find the bridged method on the implementation class...
|
// Let's try to find the bridged method on the implementation class...
|
||||||
methodToValidate = BridgeMethodResolver.findBridgedMethod(
|
methodToValidate = BridgeMethodResolver.findBridgedMethod(
|
||||||
ClassUtils.getMostSpecificMethod(invocation.getMethod(), invocation.getThis().getClass()));
|
ClassUtils.getMostSpecificMethod(invocation.getMethod(), invocation.getThis().getClass()));
|
||||||
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateParametersMethod,
|
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateParametersMethod,
|
||||||
execVal, invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
|
execVal, invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
|
||||||
}
|
}
|
||||||
if (!result.isEmpty()) {
|
if (!result.isEmpty()) {
|
||||||
throw new ConstraintViolationException(result);
|
throw new ConstraintViolationException(result);
|
||||||
}
|
|
||||||
|
|
||||||
Object returnValue = invocation.proceed();
|
|
||||||
|
|
||||||
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateReturnValueMethod,
|
|
||||||
execVal, invocation.getThis(), methodToValidate, returnValue, groups);
|
|
||||||
if (!result.isEmpty()) {
|
|
||||||
throw new ConstraintViolationException(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return returnValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
Object returnValue = invocation.proceed();
|
||||||
// Hibernate Validator 4.3's native API
|
|
||||||
return HibernateValidatorDelegate.invokeWithinValidation(invocation, this.validator, groups);
|
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateReturnValueMethod,
|
||||||
|
execVal, invocation.getThis(), methodToValidate, returnValue, groups);
|
||||||
|
if (!result.isEmpty()) {
|
||||||
|
throw new ConstraintViolationException(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -168,36 +158,4 @@ public class MethodValidationInterceptor implements MethodInterceptor {
|
||||||
return (validatedAnn != null ? validatedAnn.value() : new Class<?>[0]);
|
return (validatedAnn != null ? validatedAnn.value() : new Class<?>[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inner class to avoid a hard-coded Hibernate Validator 4.3 dependency.
|
|
||||||
*/
|
|
||||||
private static class HibernateValidatorDelegate {
|
|
||||||
|
|
||||||
public static ValidatorFactory buildValidatorFactory() {
|
|
||||||
return Validation.byProvider(HibernateValidator.class).configure().buildValidatorFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public static Object invokeWithinValidation(MethodInvocation invocation, Validator validator, Class<?>[] groups)
|
|
||||||
throws Throwable {
|
|
||||||
|
|
||||||
org.hibernate.validator.method.MethodValidator methodValidator =
|
|
||||||
validator.unwrap(org.hibernate.validator.method.MethodValidator.class);
|
|
||||||
Set<org.hibernate.validator.method.MethodConstraintViolation<Object>> result =
|
|
||||||
methodValidator.validateAllParameters(
|
|
||||||
invocation.getThis(), invocation.getMethod(), invocation.getArguments(), groups);
|
|
||||||
if (!result.isEmpty()) {
|
|
||||||
throw new org.hibernate.validator.method.MethodConstraintViolationException(result);
|
|
||||||
}
|
|
||||||
Object returnValue = invocation.proceed();
|
|
||||||
result = methodValidator.validateReturnValue(
|
|
||||||
invocation.getThis(), invocation.getMethod(), returnValue, groups);
|
|
||||||
if (!result.isEmpty()) {
|
|
||||||
throw new org.hibernate.validator.method.MethodConstraintViolationException(result);
|
|
||||||
}
|
|
||||||
return returnValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import javax.validation.ConstraintViolation;
|
import javax.validation.ConstraintViolation;
|
||||||
|
import javax.validation.executable.ExecutableValidator;
|
||||||
import javax.validation.metadata.BeanDescriptor;
|
import javax.validation.metadata.BeanDescriptor;
|
||||||
import javax.validation.metadata.ConstraintDescriptor;
|
import javax.validation.metadata.ConstraintDescriptor;
|
||||||
|
|
||||||
|
|
@ -299,6 +300,11 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation.
|
||||||
return (type != null ? this.targetValidator.unwrap(type) : (T) this.targetValidator);
|
return (type != null ? this.targetValidator.unwrap(type) : (T) this.targetValidator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExecutableValidator forExecutables() {
|
||||||
|
return this.targetValidator.forExecutables();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for a String attribute which can be resolved via a {@code MessageSource},
|
* Wrapper for a String attribute which can be resolved via a {@code MessageSource},
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2014 the original author or authors.
|
* Copyright 2002-2015 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -31,10 +31,9 @@ import org.springframework.tests.sample.beans.TestBean;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tested against Hibernate Validator 4.3, as of Spring 4.0.
|
* Tested against Hibernate Validator 5.x.
|
||||||
*
|
*
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @since 3.0
|
|
||||||
*/
|
*/
|
||||||
public class BeanValidationPostProcessorTests {
|
public class BeanValidationPostProcessorTests {
|
||||||
|
|
||||||
|
|
@ -52,6 +51,7 @@ public class BeanValidationPostProcessorTests {
|
||||||
assertTrue(ex.getRootCause().getMessage().contains("testBean"));
|
assertTrue(ex.getRootCause().getMessage().contains("testBean"));
|
||||||
assertTrue(ex.getRootCause().getMessage().contains("invalid"));
|
assertTrue(ex.getRootCause().getMessage().contains("invalid"));
|
||||||
}
|
}
|
||||||
|
ac.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -63,6 +63,7 @@ public class BeanValidationPostProcessorTests {
|
||||||
bd.getPropertyValues().add("testBean", new TestBean());
|
bd.getPropertyValues().add("testBean", new TestBean());
|
||||||
ac.registerBeanDefinition("bean", bd);
|
ac.registerBeanDefinition("bean", bd);
|
||||||
ac.refresh();
|
ac.refresh();
|
||||||
|
ac.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -74,6 +75,7 @@ public class BeanValidationPostProcessorTests {
|
||||||
ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class));
|
ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class));
|
||||||
ac.registerBeanDefinition("bean", new RootBeanDefinition(AfterInitConstraintBean.class));
|
ac.registerBeanDefinition("bean", new RootBeanDefinition(AfterInitConstraintBean.class));
|
||||||
ac.refresh();
|
ac.refresh();
|
||||||
|
ac.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -92,6 +94,7 @@ public class BeanValidationPostProcessorTests {
|
||||||
assertTrue(ex.getRootCause().getMessage().contains("stringValue"));
|
assertTrue(ex.getRootCause().getMessage().contains("stringValue"));
|
||||||
assertTrue(ex.getRootCause().getMessage().contains("invalid"));
|
assertTrue(ex.getRootCause().getMessage().contains("invalid"));
|
||||||
}
|
}
|
||||||
|
ac.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -103,6 +106,7 @@ public class BeanValidationPostProcessorTests {
|
||||||
bd.getPropertyValues().add("stringValue", "ss");
|
bd.getPropertyValues().add("stringValue", "ss");
|
||||||
ac.registerBeanDefinition("bean", bd);
|
ac.registerBeanDefinition("bean", bd);
|
||||||
ac.refresh();
|
ac.refresh();
|
||||||
|
ac.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -35,11 +35,11 @@ import org.springframework.validation.annotation.Validated;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tested against Hibernate Validator 4.3, as of Spring 4.0.
|
* Tests against Hibernate Validator 5.x.
|
||||||
*
|
*
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @since 3.1
|
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
public class MethodValidationTests {
|
public class MethodValidationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -65,6 +65,7 @@ public class MethodValidationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
private void doTestProxyValidation(MyValidInterface proxy) {
|
private void doTestProxyValidation(MyValidInterface proxy) {
|
||||||
assertNotNull(proxy.myValidMethod("value", 5));
|
assertNotNull(proxy.myValidMethod("value", 5));
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2014 the original author or authors.
|
* Copyright 2002-2015 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -38,6 +38,10 @@ import javax.validation.constraints.NotNull;
|
||||||
import org.hibernate.validator.HibernateValidator;
|
import org.hibernate.validator.HibernateValidator;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.validation.BeanPropertyBindingResult;
|
import org.springframework.validation.BeanPropertyBindingResult;
|
||||||
import org.springframework.validation.Errors;
|
import org.springframework.validation.Errors;
|
||||||
import org.springframework.validation.FieldError;
|
import org.springframework.validation.FieldError;
|
||||||
|
|
@ -47,10 +51,9 @@ import static org.hamcrest.Matchers.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tested against Hibernate Validator 4.3, as of Spring 4.0.
|
* Tests against Hibernate Validator 5.x.
|
||||||
*
|
*
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @since 3.0
|
|
||||||
*/
|
*/
|
||||||
public class ValidatorFactoryTests {
|
public class ValidatorFactoryTests {
|
||||||
|
|
||||||
|
|
@ -58,6 +61,7 @@ public class ValidatorFactoryTests {
|
||||||
public void testSimpleValidation() throws Exception {
|
public void testSimpleValidation() throws Exception {
|
||||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||||
validator.afterPropertiesSet();
|
validator.afterPropertiesSet();
|
||||||
|
|
||||||
ValidPerson person = new ValidPerson();
|
ValidPerson person = new ValidPerson();
|
||||||
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person);
|
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person);
|
||||||
assertEquals(2, result.size());
|
assertEquals(2, result.size());
|
||||||
|
|
@ -78,6 +82,7 @@ public class ValidatorFactoryTests {
|
||||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||||
validator.setProviderClass(HibernateValidator.class);
|
validator.setProviderClass(HibernateValidator.class);
|
||||||
validator.afterPropertiesSet();
|
validator.afterPropertiesSet();
|
||||||
|
|
||||||
ValidPerson person = new ValidPerson();
|
ValidPerson person = new ValidPerson();
|
||||||
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person);
|
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person);
|
||||||
assertEquals(2, result.size());
|
assertEquals(2, result.size());
|
||||||
|
|
@ -112,6 +117,7 @@ public class ValidatorFactoryTests {
|
||||||
public void testSpringValidationFieldType() throws Exception {
|
public void testSpringValidationFieldType() throws Exception {
|
||||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||||
validator.afterPropertiesSet();
|
validator.afterPropertiesSet();
|
||||||
|
|
||||||
ValidPerson person = new ValidPerson();
|
ValidPerson person = new ValidPerson();
|
||||||
person.setName("Phil");
|
person.setName("Phil");
|
||||||
person.getAddress().setStreet("Phil's Street");
|
person.getAddress().setStreet("Phil's Street");
|
||||||
|
|
@ -126,6 +132,7 @@ public class ValidatorFactoryTests {
|
||||||
public void testSpringValidation() throws Exception {
|
public void testSpringValidation() throws Exception {
|
||||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||||
validator.afterPropertiesSet();
|
validator.afterPropertiesSet();
|
||||||
|
|
||||||
ValidPerson person = new ValidPerson();
|
ValidPerson person = new ValidPerson();
|
||||||
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
|
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
|
||||||
validator.validate(person, result);
|
validator.validate(person, result);
|
||||||
|
|
@ -153,6 +160,7 @@ public class ValidatorFactoryTests {
|
||||||
public void testSpringValidationWithClassLevel() throws Exception {
|
public void testSpringValidationWithClassLevel() throws Exception {
|
||||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||||
validator.afterPropertiesSet();
|
validator.afterPropertiesSet();
|
||||||
|
|
||||||
ValidPerson person = new ValidPerson();
|
ValidPerson person = new ValidPerson();
|
||||||
person.setName("Juergen");
|
person.setName("Juergen");
|
||||||
person.getAddress().setStreet("Juergen's Street");
|
person.getAddress().setStreet("Juergen's Street");
|
||||||
|
|
@ -166,10 +174,32 @@ public class ValidatorFactoryTests {
|
||||||
assertTrue(errorCodes.contains("NameAddressValid"));
|
assertTrue(errorCodes.contains("NameAddressValid"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSpringValidationWithAutowiredValidator() throws Exception {
|
||||||
|
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(
|
||||||
|
LocalValidatorFactoryBean.class);
|
||||||
|
LocalValidatorFactoryBean validator = ctx.getBean(LocalValidatorFactoryBean.class);
|
||||||
|
|
||||||
|
ValidPerson person = new ValidPerson();
|
||||||
|
person.expectsAutowiredValidator = true;
|
||||||
|
person.setName("Juergen");
|
||||||
|
person.getAddress().setStreet("Juergen's Street");
|
||||||
|
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
|
||||||
|
validator.validate(person, result);
|
||||||
|
assertEquals(1, result.getErrorCount());
|
||||||
|
ObjectError globalError = result.getGlobalError();
|
||||||
|
List<String> errorCodes = Arrays.asList(globalError.getCodes());
|
||||||
|
assertEquals(2, errorCodes.size());
|
||||||
|
assertTrue(errorCodes.contains("NameAddressValid.person"));
|
||||||
|
assertTrue(errorCodes.contains("NameAddressValid"));
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSpringValidationWithErrorInListElement() throws Exception {
|
public void testSpringValidationWithErrorInListElement() throws Exception {
|
||||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||||
validator.afterPropertiesSet();
|
validator.afterPropertiesSet();
|
||||||
|
|
||||||
ValidPerson person = new ValidPerson();
|
ValidPerson person = new ValidPerson();
|
||||||
person.getAddressList().add(new ValidAddress());
|
person.getAddressList().add(new ValidAddress());
|
||||||
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
|
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
|
||||||
|
|
@ -187,6 +217,7 @@ public class ValidatorFactoryTests {
|
||||||
public void testSpringValidationWithErrorInSetElement() throws Exception {
|
public void testSpringValidationWithErrorInSetElement() throws Exception {
|
||||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||||
validator.afterPropertiesSet();
|
validator.afterPropertiesSet();
|
||||||
|
|
||||||
ValidPerson person = new ValidPerson();
|
ValidPerson person = new ValidPerson();
|
||||||
person.getAddressSet().add(new ValidAddress());
|
person.getAddressSet().add(new ValidAddress());
|
||||||
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
|
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
|
||||||
|
|
@ -240,6 +271,8 @@ public class ValidatorFactoryTests {
|
||||||
@Valid
|
@Valid
|
||||||
private Set<ValidAddress> addressSet = new LinkedHashSet<ValidAddress>();
|
private Set<ValidAddress> addressSet = new LinkedHashSet<ValidAddress>();
|
||||||
|
|
||||||
|
public boolean expectsAutowiredValidator = false;
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
@ -304,16 +337,22 @@ public class ValidatorFactoryTests {
|
||||||
|
|
||||||
public static class NameAddressValidator implements ConstraintValidator<NameAddressValid, ValidPerson> {
|
public static class NameAddressValidator implements ConstraintValidator<NameAddressValid, ValidPerson> {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Environment environment;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(NameAddressValid constraintAnnotation) {
|
public void initialize(NameAddressValid constraintAnnotation) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValid(ValidPerson value, ConstraintValidatorContext context) {
|
public boolean isValid(ValidPerson value, ConstraintValidatorContext context) {
|
||||||
|
if (value.expectsAutowiredValidator) {
|
||||||
|
assertNotNull(this.environment);
|
||||||
|
}
|
||||||
boolean valid = (value.name == null || !value.address.street.contains(value.name));
|
boolean valid = (value.name == null || !value.address.street.contains(value.name));
|
||||||
if (!valid && "Phil".equals(value.name)) {
|
if (!valid && "Phil".equals(value.name)) {
|
||||||
context.buildConstraintViolationWithTemplate(
|
context.buildConstraintViolationWithTemplate(
|
||||||
context.getDefaultConstraintMessageTemplate()).addNode("address").addConstraintViolation().disableDefaultConstraintViolation();
|
context.getDefaultConstraintMessageTemplate()).addPropertyNode("address").addConstraintViolation().disableDefaultConstraintViolation();
|
||||||
}
|
}
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
@ -378,7 +417,7 @@ public class ValidatorFactoryTests {
|
||||||
public boolean isValid(InnerBean bean, ConstraintValidatorContext context) {
|
public boolean isValid(InnerBean bean, ConstraintValidatorContext context) {
|
||||||
context.disableDefaultConstraintViolation();
|
context.disableDefaultConstraintViolation();
|
||||||
if (bean.getValue() == null) {
|
if (bean.getValue() == null) {
|
||||||
context.buildConstraintViolationWithTemplate("NULL"). addNode("value").addConstraintViolation();
|
context.buildConstraintViolationWithTemplate("NULL").addPropertyNode("value").addConstraintViolation();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -1,161 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationHandler;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Proxy;
|
|
||||||
import javax.transaction.Status;
|
|
||||||
import javax.transaction.Synchronization;
|
|
||||||
import javax.transaction.SystemException;
|
|
||||||
import javax.transaction.Transaction;
|
|
||||||
import javax.transaction.TransactionManager;
|
|
||||||
import javax.transaction.TransactionSynchronizationRegistry;
|
|
||||||
import javax.transaction.UserTransaction;
|
|
||||||
|
|
||||||
import org.hibernate.TransactionException;
|
|
||||||
import org.hibernate.service.Service;
|
|
||||||
|
|
||||||
import org.springframework.transaction.jta.UserTransactionAdapter;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of Hibernate 4's JtaPlatform SPI (which has a different package
|
|
||||||
* location in Hibernate 4.0-4.2 vs 4.3), exposing passed-in {@link TransactionManager},
|
|
||||||
* {@link UserTransaction} and {@link TransactionSynchronizationRegistry} references.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1.2
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({"serial", "unchecked"})
|
|
||||||
class ConfigurableJtaPlatform implements InvocationHandler {
|
|
||||||
|
|
||||||
static final Class<? extends Service> jtaPlatformClass;
|
|
||||||
|
|
||||||
static {
|
|
||||||
Class<?> jpClass;
|
|
||||||
try {
|
|
||||||
// Try Hibernate 4.0-4.2 JtaPlatform variant
|
|
||||||
jpClass = ClassUtils.forName("org.hibernate.service.jta.platform.spi.JtaPlatform",
|
|
||||||
ConfigurableJtaPlatform.class.getClassLoader());
|
|
||||||
}
|
|
||||||
catch (ClassNotFoundException ex) {
|
|
||||||
try {
|
|
||||||
// Try Hibernate 4.3 JtaPlatform variant
|
|
||||||
jpClass = ClassUtils.forName("org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform",
|
|
||||||
ConfigurableJtaPlatform.class.getClassLoader());
|
|
||||||
}
|
|
||||||
catch (ClassNotFoundException ex2) {
|
|
||||||
throw new IllegalStateException("Neither Hibernate 4.0-4.2 nor 4.3 variant of JtaPlatform found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jtaPlatformClass = (Class<? extends Service>) jpClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
static String getJtaPlatformBasePackage() {
|
|
||||||
String className = jtaPlatformClass.getName();
|
|
||||||
return className.substring(0, className.length() - "spi.JtaPlatform".length());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private final TransactionManager transactionManager;
|
|
||||||
|
|
||||||
private final UserTransaction userTransaction;
|
|
||||||
|
|
||||||
private final TransactionSynchronizationRegistry transactionSynchronizationRegistry;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new ConfigurableJtaPlatform instance with the given
|
|
||||||
* JTA TransactionManager and optionally a given UserTransaction.
|
|
||||||
* @param tm the JTA TransactionManager reference (required)
|
|
||||||
* @param ut the JTA UserTransaction reference (optional)
|
|
||||||
* @param tsr the JTA 1.1 TransactionSynchronizationRegistry (optional)
|
|
||||||
*/
|
|
||||||
public ConfigurableJtaPlatform(TransactionManager tm, UserTransaction ut, TransactionSynchronizationRegistry tsr) {
|
|
||||||
Assert.notNull(tm, "TransactionManager reference must not be null");
|
|
||||||
this.transactionManager = tm;
|
|
||||||
this.userTransaction = (ut != null ? ut : new UserTransactionAdapter(tm));
|
|
||||||
this.transactionSynchronizationRegistry = tsr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public TransactionManager retrieveTransactionManager() {
|
|
||||||
return this.transactionManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserTransaction retrieveUserTransaction() {
|
|
||||||
return this.userTransaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getTransactionIdentifier(Transaction transaction) {
|
|
||||||
return transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean canRegisterSynchronization() {
|
|
||||||
try {
|
|
||||||
return (this.transactionManager.getStatus() == Status.STATUS_ACTIVE);
|
|
||||||
}
|
|
||||||
catch (SystemException ex) {
|
|
||||||
throw new TransactionException("Could not determine JTA transaction status", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerSynchronization(Synchronization synchronization) {
|
|
||||||
if (this.transactionSynchronizationRegistry != null) {
|
|
||||||
this.transactionSynchronizationRegistry.registerInterposedSynchronization(synchronization);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
try {
|
|
||||||
this.transactionManager.getTransaction().registerSynchronization(synchronization);
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new TransactionException("Could not access JTA Transaction to register synchronization", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCurrentStatus() throws SystemException {
|
|
||||||
return this.transactionManager.getStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
|
||||||
try {
|
|
||||||
return getClass().getMethod(method.getName(), method.getParameterTypes()).invoke(this, args);
|
|
||||||
}
|
|
||||||
catch (InvocationTargetException ex) {
|
|
||||||
throw ex.getTargetException();
|
|
||||||
}
|
|
||||||
catch (Throwable ex) {
|
|
||||||
throw new IllegalStateException("Failed to delegate to corresponding implementation method", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain a proxy that implements the current Hibernate version's JtaPlatform interface
|
|
||||||
* in the right package location, delegating all invocations to the same-named methods
|
|
||||||
* on this ConfigurableJtaPlatform class itself.
|
|
||||||
*/
|
|
||||||
public Object getJtaPlatformProxy() {
|
|
||||||
return Proxy.newProxyInstance(getClass().getClassLoader(), new Class<?>[] {jtaPlatformClass}, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2016 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback interface for Hibernate code. To be used with {@link HibernateTemplate}'s
|
|
||||||
* execution methods, often as anonymous classes within a method implementation.
|
|
||||||
* A typical implementation will call {@code Session.load/find/update} to perform
|
|
||||||
* some operations on persistent objects.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 4.0.1
|
|
||||||
* @see HibernateTemplate
|
|
||||||
* @see HibernateTransactionManager
|
|
||||||
*/
|
|
||||||
public interface HibernateCallback<T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets called by {@code HibernateTemplate.execute} with an active
|
|
||||||
* Hibernate {@code Session}. Does not need to care about activating
|
|
||||||
* or closing the {@code Session}, or handling transactions.
|
|
||||||
* <p>Allows for returning a result object created within the callback,
|
|
||||||
* i.e. a domain object or a collection of domain objects.
|
|
||||||
* A thrown custom RuntimeException is treated as an application exception:
|
|
||||||
* It gets propagated to the caller of the template.
|
|
||||||
* @param session active Hibernate session
|
|
||||||
* @return a result object, or {@code null} if none
|
|
||||||
* @throws HibernateException if thrown by the Hibernate API
|
|
||||||
* @see HibernateTemplate#execute
|
|
||||||
*/
|
|
||||||
T doInHibernate(Session session) throws HibernateException;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException;
|
|
||||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link PersistenceExceptionTranslator} capable of translating {@link HibernateException}
|
|
||||||
* instances to Spring's {@link DataAccessException} hierarchy.
|
|
||||||
*
|
|
||||||
* <p>Extended by {@link LocalSessionFactoryBean}, so there is no need to declare this
|
|
||||||
* translator in addition to a {@code LocalSessionFactoryBean}.
|
|
||||||
*
|
|
||||||
* <p>When configuring the container with {@code @Configuration} classes, a {@code @Bean}
|
|
||||||
* of this type must be registered manually.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
* @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
|
|
||||||
* @see SessionFactoryUtils#convertHibernateAccessException(HibernateException)
|
|
||||||
*/
|
|
||||||
public class HibernateExceptionTranslator implements PersistenceExceptionTranslator {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
|
|
||||||
if (ex instanceof HibernateException) {
|
|
||||||
return convertHibernateAccessException((HibernateException) ex);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the given HibernateException to an appropriate exception from the
|
|
||||||
* {@code org.springframework.dao} hierarchy.
|
|
||||||
* @param ex HibernateException that occured
|
|
||||||
* @return a corresponding DataAccessException
|
|
||||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
|
||||||
*/
|
|
||||||
protected DataAccessException convertHibernateAccessException(HibernateException ex) {
|
|
||||||
return SessionFactoryUtils.convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
import org.hibernate.JDBCException;
|
|
||||||
|
|
||||||
import org.springframework.dao.UncategorizedDataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate-specific subclass of UncategorizedDataAccessException,
|
|
||||||
* for JDBC exceptions that Hibernate wrapped.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class HibernateJdbcException extends UncategorizedDataAccessException {
|
|
||||||
|
|
||||||
public HibernateJdbcException(JDBCException ex) {
|
|
||||||
super("JDBC exception on Hibernate data access: SQLException for SQL [" + ex.getSQL() + "]; SQL state [" +
|
|
||||||
ex.getSQLState() + "]; error code [" + ex.getErrorCode() + "]; " + ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the underlying SQLException.
|
|
||||||
*/
|
|
||||||
public SQLException getSQLException() {
|
|
||||||
return ((JDBCException) getCause()).getSQLException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the SQL that led to the problem.
|
|
||||||
*/
|
|
||||||
public String getSql() {
|
|
||||||
return ((JDBCException) getCause()).getSQL();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
||||||
import org.hibernate.UnresolvableObjectException;
|
|
||||||
import org.hibernate.WrongClassException;
|
|
||||||
|
|
||||||
import org.springframework.orm.ObjectRetrievalFailureException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate-specific subclass of ObjectRetrievalFailureException.
|
|
||||||
* Converts Hibernate's UnresolvableObjectException and WrongClassException.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class HibernateObjectRetrievalFailureException extends ObjectRetrievalFailureException {
|
|
||||||
|
|
||||||
public HibernateObjectRetrievalFailureException(UnresolvableObjectException ex) {
|
|
||||||
super(ex.getEntityName(), ex.getIdentifier(), ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HibernateObjectRetrievalFailureException(WrongClassException ex) {
|
|
||||||
super(ex.getEntityName(), ex.getIdentifier(), ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,795 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.hibernate.Filter;
|
|
||||||
import org.hibernate.LockMode;
|
|
||||||
import org.hibernate.ReplicationMode;
|
|
||||||
import org.hibernate.criterion.DetachedCriteria;
|
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface that specifies a basic set of Hibernate operations,
|
|
||||||
* implemented by {@link HibernateTemplate}. Not often used, but a useful
|
|
||||||
* option to enhance testability, as it can easily be mocked or stubbed.
|
|
||||||
*
|
|
||||||
* <p>Defines {@code HibernateTemplate}'s data access methods that
|
|
||||||
* mirror various {@link org.hibernate.Session} methods. Users are
|
|
||||||
* strongly encouraged to read the Hibernate {@code Session} javadocs
|
|
||||||
* for details on the semantics of those methods.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 4.0.1
|
|
||||||
* @see HibernateTemplate
|
|
||||||
* @see org.hibernate.Session
|
|
||||||
* @see HibernateTransactionManager
|
|
||||||
*/
|
|
||||||
public interface HibernateOperations {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the action specified by the given action object within a
|
|
||||||
* {@link org.hibernate.Session}.
|
|
||||||
* <p>Application exceptions thrown by the action object get propagated
|
|
||||||
* to the caller (can only be unchecked). Hibernate exceptions are
|
|
||||||
* transformed into appropriate DAO ones. Allows for returning a result
|
|
||||||
* object, that is a domain object or a collection of domain objects.
|
|
||||||
* <p>Note: Callback code is not supposed to handle transactions itself!
|
|
||||||
* Use an appropriate transaction manager like
|
|
||||||
* {@link HibernateTransactionManager}. Generally, callback code must not
|
|
||||||
* touch any {@code Session} lifecycle methods, like close,
|
|
||||||
* disconnect, or reconnect, to let the template do its work.
|
|
||||||
* @param action callback object that specifies the Hibernate action
|
|
||||||
* @return a result object returned by the action, or {@code null}
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see HibernateTransactionManager
|
|
||||||
* @see org.hibernate.Session
|
|
||||||
*/
|
|
||||||
<T> T execute(HibernateCallback<T> action) throws DataAccessException;
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
// Convenience methods for loading individual objects
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the persistent instance of the given entity class
|
|
||||||
* with the given identifier, or {@code null} if not found.
|
|
||||||
* <p>This method is a thin wrapper around
|
|
||||||
* {@link org.hibernate.Session#get(Class, java.io.Serializable)} for convenience.
|
|
||||||
* For an explanation of the exact semantics of this method, please do refer to
|
|
||||||
* the Hibernate API documentation in the first instance.
|
|
||||||
* @param entityClass a persistent class
|
|
||||||
* @param id the identifier of the persistent instance
|
|
||||||
* @return the persistent instance, or {@code null} if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#get(Class, java.io.Serializable)
|
|
||||||
*/
|
|
||||||
<T> T get(Class<T> entityClass, Serializable id) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the persistent instance of the given entity class
|
|
||||||
* with the given identifier, or {@code null} if not found.
|
|
||||||
* <p>Obtains the specified lock mode if the instance exists.
|
|
||||||
* <p>This method is a thin wrapper around
|
|
||||||
* {@link org.hibernate.Session#get(Class, java.io.Serializable, LockMode)} for convenience.
|
|
||||||
* For an explanation of the exact semantics of this method, please do refer to
|
|
||||||
* the Hibernate API documentation in the first instance.
|
|
||||||
* @param entityClass a persistent class
|
|
||||||
* @param id the identifier of the persistent instance
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @return the persistent instance, or {@code null} if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#get(Class, java.io.Serializable, org.hibernate.LockMode)
|
|
||||||
*/
|
|
||||||
<T> T get(Class<T> entityClass, Serializable id, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the persistent instance of the given entity class
|
|
||||||
* with the given identifier, or {@code null} if not found.
|
|
||||||
* <p>This method is a thin wrapper around
|
|
||||||
* {@link org.hibernate.Session#get(String, java.io.Serializable)} for convenience.
|
|
||||||
* For an explanation of the exact semantics of this method, please do refer to
|
|
||||||
* the Hibernate API documentation in the first instance.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param id the identifier of the persistent instance
|
|
||||||
* @return the persistent instance, or {@code null} if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#get(Class, java.io.Serializable)
|
|
||||||
*/
|
|
||||||
Object get(String entityName, Serializable id) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the persistent instance of the given entity class
|
|
||||||
* with the given identifier, or {@code null} if not found.
|
|
||||||
* Obtains the specified lock mode if the instance exists.
|
|
||||||
* <p>This method is a thin wrapper around
|
|
||||||
* {@link org.hibernate.Session#get(String, java.io.Serializable, LockMode)} for convenience.
|
|
||||||
* For an explanation of the exact semantics of this method, please do refer to
|
|
||||||
* the Hibernate API documentation in the first instance.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param id the identifier of the persistent instance
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @return the persistent instance, or {@code null} if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#get(Class, java.io.Serializable, org.hibernate.LockMode)
|
|
||||||
*/
|
|
||||||
Object get(String entityName, Serializable id, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the persistent instance of the given entity class
|
|
||||||
* with the given identifier, throwing an exception if not found.
|
|
||||||
* <p>This method is a thin wrapper around
|
|
||||||
* {@link org.hibernate.Session#load(Class, java.io.Serializable)} for convenience.
|
|
||||||
* For an explanation of the exact semantics of this method, please do refer to
|
|
||||||
* the Hibernate API documentation in the first instance.
|
|
||||||
* @param entityClass a persistent class
|
|
||||||
* @param id the identifier of the persistent instance
|
|
||||||
* @return the persistent instance
|
|
||||||
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#load(Class, java.io.Serializable)
|
|
||||||
*/
|
|
||||||
<T> T load(Class<T> entityClass, Serializable id) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the persistent instance of the given entity class
|
|
||||||
* with the given identifier, throwing an exception if not found.
|
|
||||||
* Obtains the specified lock mode if the instance exists.
|
|
||||||
* <p>This method is a thin wrapper around
|
|
||||||
* {@link org.hibernate.Session#load(Class, java.io.Serializable, LockMode)} for convenience.
|
|
||||||
* For an explanation of the exact semantics of this method, please do refer to
|
|
||||||
* the Hibernate API documentation in the first instance.
|
|
||||||
* @param entityClass a persistent class
|
|
||||||
* @param id the identifier of the persistent instance
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @return the persistent instance
|
|
||||||
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#load(Class, java.io.Serializable)
|
|
||||||
*/
|
|
||||||
<T> T load(Class<T> entityClass, Serializable id, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the persistent instance of the given entity class
|
|
||||||
* with the given identifier, throwing an exception if not found.
|
|
||||||
* <p>This method is a thin wrapper around
|
|
||||||
* {@link org.hibernate.Session#load(String, java.io.Serializable)} for convenience.
|
|
||||||
* For an explanation of the exact semantics of this method, please do refer to
|
|
||||||
* the Hibernate API documentation in the first instance.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param id the identifier of the persistent instance
|
|
||||||
* @return the persistent instance
|
|
||||||
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#load(Class, java.io.Serializable)
|
|
||||||
*/
|
|
||||||
Object load(String entityName, Serializable id) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the persistent instance of the given entity class
|
|
||||||
* with the given identifier, throwing an exception if not found.
|
|
||||||
* <p>Obtains the specified lock mode if the instance exists.
|
|
||||||
* <p>This method is a thin wrapper around
|
|
||||||
* {@link org.hibernate.Session#load(String, java.io.Serializable, LockMode)} for convenience.
|
|
||||||
* For an explanation of the exact semantics of this method, please do refer to
|
|
||||||
* the Hibernate API documentation in the first instance.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param id the identifier of the persistent instance
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @return the persistent instance
|
|
||||||
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#load(Class, java.io.Serializable)
|
|
||||||
*/
|
|
||||||
Object load(String entityName, Serializable id, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return all persistent instances of the given entity class.
|
|
||||||
* Note: Use queries or criteria for retrieving a specific subset.
|
|
||||||
* @param entityClass a persistent class
|
|
||||||
* @return a {@link List} containing 0 or more persistent instances
|
|
||||||
* @throws org.springframework.dao.DataAccessException if there is a Hibernate error
|
|
||||||
* @see org.hibernate.Session#createCriteria
|
|
||||||
*/
|
|
||||||
<T> List<T> loadAll(Class<T> entityClass) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the persistent instance with the given identifier
|
|
||||||
* into the given object, throwing an exception if not found.
|
|
||||||
* <p>This method is a thin wrapper around
|
|
||||||
* {@link org.hibernate.Session#load(Object, java.io.Serializable)} for convenience.
|
|
||||||
* For an explanation of the exact semantics of this method, please do refer to
|
|
||||||
* the Hibernate API documentation in the first instance.
|
|
||||||
* @param entity the object (of the target class) to load into
|
|
||||||
* @param id the identifier of the persistent instance
|
|
||||||
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#load(Object, java.io.Serializable)
|
|
||||||
*/
|
|
||||||
void load(Object entity, Serializable id) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Re-read the state of the given persistent instance.
|
|
||||||
* @param entity the persistent instance to re-read
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#refresh(Object)
|
|
||||||
*/
|
|
||||||
void refresh(Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Re-read the state of the given persistent instance.
|
|
||||||
* Obtains the specified lock mode for the instance.
|
|
||||||
* @param entity the persistent instance to re-read
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#refresh(Object, org.hibernate.LockMode)
|
|
||||||
*/
|
|
||||||
void refresh(Object entity, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether the given object is in the Session cache.
|
|
||||||
* @param entity the persistence instance to check
|
|
||||||
* @return whether the given object is in the Session cache
|
|
||||||
* @throws org.springframework.dao.DataAccessException if there is a Hibernate error
|
|
||||||
* @see org.hibernate.Session#contains
|
|
||||||
*/
|
|
||||||
boolean contains(Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the given object from the {@link org.hibernate.Session} cache.
|
|
||||||
* @param entity the persistent instance to evict
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#evict
|
|
||||||
*/
|
|
||||||
void evict(Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Force initialization of a Hibernate proxy or persistent collection.
|
|
||||||
* @param proxy a proxy for a persistent object or a persistent collection
|
|
||||||
* @throws DataAccessException if we can't initialize the proxy, for example
|
|
||||||
* because it is not associated with an active Session
|
|
||||||
* @see org.hibernate.Hibernate#initialize
|
|
||||||
*/
|
|
||||||
void initialize(Object proxy) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an enabled Hibernate {@link Filter} for the given filter name.
|
|
||||||
* The returned {@code Filter} instance can be used to set filter parameters.
|
|
||||||
* @param filterName the name of the filter
|
|
||||||
* @return the enabled Hibernate {@code Filter} (either already
|
|
||||||
* enabled or enabled on the fly by this operation)
|
|
||||||
* @throws IllegalStateException if we are not running within a
|
|
||||||
* transactional Session (in which case this operation does not make sense)
|
|
||||||
*/
|
|
||||||
Filter enableFilter(String filterName) throws IllegalStateException;
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
// Convenience methods for storing individual objects
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the specified lock level upon the given object, implicitly
|
|
||||||
* checking whether the corresponding database entry still exists.
|
|
||||||
* @param entity the persistent instance to lock
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#lock(Object, org.hibernate.LockMode)
|
|
||||||
*/
|
|
||||||
void lock(Object entity, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the specified lock level upon the given object, implicitly
|
|
||||||
* checking whether the corresponding database entry still exists.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the persistent instance to lock
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#lock(String, Object, org.hibernate.LockMode)
|
|
||||||
*/
|
|
||||||
void lock(String entityName, Object entity, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persist the given transient instance.
|
|
||||||
* @param entity the transient instance to persist
|
|
||||||
* @return the generated identifier
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#save(Object)
|
|
||||||
*/
|
|
||||||
Serializable save(Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persist the given transient instance.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the transient instance to persist
|
|
||||||
* @return the generated identifier
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#save(String, Object)
|
|
||||||
*/
|
|
||||||
Serializable save(String entityName, Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the given persistent instance,
|
|
||||||
* associating it with the current Hibernate {@link org.hibernate.Session}.
|
|
||||||
* @param entity the persistent instance to update
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#update(Object)
|
|
||||||
*/
|
|
||||||
void update(Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the given persistent instance,
|
|
||||||
* associating it with the current Hibernate {@link org.hibernate.Session}.
|
|
||||||
* <p>Obtains the specified lock mode if the instance exists, implicitly
|
|
||||||
* checking whether the corresponding database entry still exists.
|
|
||||||
* @param entity the persistent instance to update
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#update(Object)
|
|
||||||
*/
|
|
||||||
void update(Object entity, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the given persistent instance,
|
|
||||||
* associating it with the current Hibernate {@link org.hibernate.Session}.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the persistent instance to update
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#update(String, Object)
|
|
||||||
*/
|
|
||||||
void update(String entityName, Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the given persistent instance,
|
|
||||||
* associating it with the current Hibernate {@link org.hibernate.Session}.
|
|
||||||
* <p>Obtains the specified lock mode if the instance exists, implicitly
|
|
||||||
* checking whether the corresponding database entry still exists.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the persistent instance to update
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#update(String, Object)
|
|
||||||
*/
|
|
||||||
void update(String entityName, Object entity, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save or update the given persistent instance,
|
|
||||||
* according to its id (matching the configured "unsaved-value"?).
|
|
||||||
* Associates the instance with the current Hibernate {@link org.hibernate.Session}.
|
|
||||||
* @param entity the persistent instance to save or update
|
|
||||||
* (to be associated with the Hibernate {@code Session})
|
|
||||||
* @throws DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#saveOrUpdate(Object)
|
|
||||||
*/
|
|
||||||
void saveOrUpdate(Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save or update the given persistent instance,
|
|
||||||
* according to its id (matching the configured "unsaved-value"?).
|
|
||||||
* Associates the instance with the current Hibernate {@code Session}.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the persistent instance to save or update
|
|
||||||
* (to be associated with the Hibernate {@code Session})
|
|
||||||
* @throws DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#saveOrUpdate(String, Object)
|
|
||||||
*/
|
|
||||||
void saveOrUpdate(String entityName, Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persist the state of the given detached instance according to the
|
|
||||||
* given replication mode, reusing the current identifier value.
|
|
||||||
* @param entity the persistent object to replicate
|
|
||||||
* @param replicationMode the Hibernate ReplicationMode
|
|
||||||
* @throws DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#replicate(Object, org.hibernate.ReplicationMode)
|
|
||||||
*/
|
|
||||||
void replicate(Object entity, ReplicationMode replicationMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persist the state of the given detached instance according to the
|
|
||||||
* given replication mode, reusing the current identifier value.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the persistent object to replicate
|
|
||||||
* @param replicationMode the Hibernate ReplicationMode
|
|
||||||
* @throws DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#replicate(String, Object, org.hibernate.ReplicationMode)
|
|
||||||
*/
|
|
||||||
void replicate(String entityName, Object entity, ReplicationMode replicationMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persist the given transient instance. Follows JSR-220 semantics.
|
|
||||||
* <p>Similar to {@code save}, associating the given object
|
|
||||||
* with the current Hibernate {@link org.hibernate.Session}.
|
|
||||||
* @param entity the persistent instance to persist
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#persist(Object)
|
|
||||||
* @see #save
|
|
||||||
*/
|
|
||||||
void persist(Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persist the given transient instance. Follows JSR-220 semantics.
|
|
||||||
* <p>Similar to {@code save}, associating the given object
|
|
||||||
* with the current Hibernate {@link org.hibernate.Session}.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the persistent instance to persist
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#persist(String, Object)
|
|
||||||
* @see #save
|
|
||||||
*/
|
|
||||||
void persist(String entityName, Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy the state of the given object onto the persistent object
|
|
||||||
* with the same identifier. Follows JSR-220 semantics.
|
|
||||||
* <p>Similar to {@code saveOrUpdate}, but never associates the given
|
|
||||||
* object with the current Hibernate Session. In case of a new entity,
|
|
||||||
* the state will be copied over as well.
|
|
||||||
* <p>Note that {@code merge} will <i>not</i> update the identifiers
|
|
||||||
* in the passed-in object graph (in contrast to TopLink)! Consider
|
|
||||||
* registering Spring's {@code IdTransferringMergeEventListener} if
|
|
||||||
* you would like to have newly assigned ids transferred to the original
|
|
||||||
* object graph too.
|
|
||||||
* @param entity the object to merge with the corresponding persistence instance
|
|
||||||
* @return the updated, registered persistent instance
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#merge(Object)
|
|
||||||
* @see #saveOrUpdate
|
|
||||||
*/
|
|
||||||
<T> T merge(T entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy the state of the given object onto the persistent object
|
|
||||||
* with the same identifier. Follows JSR-220 semantics.
|
|
||||||
* <p>Similar to {@code saveOrUpdate}, but never associates the given
|
|
||||||
* object with the current Hibernate {@link org.hibernate.Session}. In
|
|
||||||
* the case of a new entity, the state will be copied over as well.
|
|
||||||
* <p>Note that {@code merge} will <i>not</i> update the identifiers
|
|
||||||
* in the passed-in object graph (in contrast to TopLink)! Consider
|
|
||||||
* registering Spring's {@code IdTransferringMergeEventListener}
|
|
||||||
* if you would like to have newly assigned ids transferred to the
|
|
||||||
* original object graph too.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the object to merge with the corresponding persistence instance
|
|
||||||
* @return the updated, registered persistent instance
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#merge(String, Object)
|
|
||||||
* @see #saveOrUpdate
|
|
||||||
*/
|
|
||||||
<T> T merge(String entityName, T entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the given persistent instance.
|
|
||||||
* @param entity the persistent instance to delete
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#delete(Object)
|
|
||||||
*/
|
|
||||||
void delete(Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the given persistent instance.
|
|
||||||
* <p>Obtains the specified lock mode if the instance exists, implicitly
|
|
||||||
* checking whether the corresponding database entry still exists.
|
|
||||||
* @param entity the persistent instance to delete
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#delete(Object)
|
|
||||||
*/
|
|
||||||
void delete(Object entity, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the given persistent instance.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the persistent instance to delete
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#delete(Object)
|
|
||||||
*/
|
|
||||||
void delete(String entityName, Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the given persistent instance.
|
|
||||||
* <p>Obtains the specified lock mode if the instance exists, implicitly
|
|
||||||
* checking whether the corresponding database entry still exists.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the persistent instance to delete
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#delete(Object)
|
|
||||||
*/
|
|
||||||
void delete(String entityName, Object entity, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete all given persistent instances.
|
|
||||||
* <p>This can be combined with any of the find methods to delete by query
|
|
||||||
* in two lines of code.
|
|
||||||
* @param entities the persistent instances to delete
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#delete(Object)
|
|
||||||
*/
|
|
||||||
void deleteAll(Collection<?> entities) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flush all pending saves, updates and deletes to the database.
|
|
||||||
* <p>Only invoke this for selective eager flushing, for example when
|
|
||||||
* JDBC code needs to see certain changes within the same transaction.
|
|
||||||
* Else, it is preferable to rely on auto-flushing at transaction
|
|
||||||
* completion.
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#flush
|
|
||||||
*/
|
|
||||||
void flush() throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all objects from the {@link org.hibernate.Session} cache, and
|
|
||||||
* cancel all pending saves, updates and deletes.
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#clear
|
|
||||||
*/
|
|
||||||
void clear() throws DataAccessException;
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
// Convenience finder methods for HQL strings
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute an HQL query, binding a number of values to "?" parameters
|
|
||||||
* in the query string.
|
|
||||||
* @param queryString a query expressed in Hibernate's query language
|
|
||||||
* @param values the values of the parameters
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#createQuery
|
|
||||||
*/
|
|
||||||
List<?> find(String queryString, Object... values) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute an HQL query, binding one value to a ":" named parameter
|
|
||||||
* in the query string.
|
|
||||||
* @param queryString a query expressed in Hibernate's query language
|
|
||||||
* @param paramName the name of the parameter
|
|
||||||
* @param value the value of the parameter
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#getNamedQuery(String)
|
|
||||||
*/
|
|
||||||
List<?> findByNamedParam(String queryString, String paramName, Object value) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute an HQL query, binding a number of values to ":" named
|
|
||||||
* parameters in the query string.
|
|
||||||
* @param queryString a query expressed in Hibernate's query language
|
|
||||||
* @param paramNames the names of the parameters
|
|
||||||
* @param values the values of the parameters
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#getNamedQuery(String)
|
|
||||||
*/
|
|
||||||
List<?> findByNamedParam(String queryString, String[] paramNames, Object[] values) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute an HQL query, binding the properties of the given bean to
|
|
||||||
* <i>named</i> parameters in the query string.
|
|
||||||
* @param queryString a query expressed in Hibernate's query language
|
|
||||||
* @param valueBean the values of the parameters
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Query#setProperties
|
|
||||||
* @see org.hibernate.Session#createQuery
|
|
||||||
*/
|
|
||||||
List<?> findByValueBean(String queryString, Object valueBean) throws DataAccessException;
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
// Convenience finder methods for named queries
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a named query binding a number of values to "?" parameters
|
|
||||||
* in the query string.
|
|
||||||
* <p>A named query is defined in a Hibernate mapping file.
|
|
||||||
* @param queryName the name of a Hibernate query in a mapping file
|
|
||||||
* @param values the values of the parameters
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#getNamedQuery(String)
|
|
||||||
*/
|
|
||||||
List<?> findByNamedQuery(String queryName, Object... values) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a named query, binding one value to a ":" named parameter
|
|
||||||
* in the query string.
|
|
||||||
* <p>A named query is defined in a Hibernate mapping file.
|
|
||||||
* @param queryName the name of a Hibernate query in a mapping file
|
|
||||||
* @param paramName the name of parameter
|
|
||||||
* @param value the value of the parameter
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#getNamedQuery(String)
|
|
||||||
*/
|
|
||||||
List<?> findByNamedQueryAndNamedParam(String queryName, String paramName, Object value)
|
|
||||||
throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a named query, binding a number of values to ":" named
|
|
||||||
* parameters in the query string.
|
|
||||||
* <p>A named query is defined in a Hibernate mapping file.
|
|
||||||
* @param queryName the name of a Hibernate query in a mapping file
|
|
||||||
* @param paramNames the names of the parameters
|
|
||||||
* @param values the values of the parameters
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#getNamedQuery(String)
|
|
||||||
*/
|
|
||||||
List<?> findByNamedQueryAndNamedParam(String queryName, String[] paramNames, Object[] values)
|
|
||||||
throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a named query, binding the properties of the given bean to
|
|
||||||
* ":" named parameters in the query string.
|
|
||||||
* <p>A named query is defined in a Hibernate mapping file.
|
|
||||||
* @param queryName the name of a Hibernate query in a mapping file
|
|
||||||
* @param valueBean the values of the parameters
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Query#setProperties
|
|
||||||
* @see org.hibernate.Session#getNamedQuery(String)
|
|
||||||
*/
|
|
||||||
List<?> findByNamedQueryAndValueBean(String queryName, Object valueBean) throws DataAccessException;
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
// Convenience finder methods for detached criteria
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a query based on a given Hibernate criteria object.
|
|
||||||
* @param criteria the detached Hibernate criteria object.
|
|
||||||
* <b>Note: Do not reuse criteria objects! They need to recreated per execution,
|
|
||||||
* due to the suboptimal design of Hibernate's criteria facility.</b>
|
|
||||||
* @return a {@link List} containing 0 or more persistent instances
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.criterion.DetachedCriteria#getExecutableCriteria(org.hibernate.Session)
|
|
||||||
*/
|
|
||||||
List<?> findByCriteria(DetachedCriteria criteria) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a query based on the given Hibernate criteria object.
|
|
||||||
* @param criteria the detached Hibernate criteria object.
|
|
||||||
* <b>Note: Do not reuse criteria objects! They need to recreated per execution,
|
|
||||||
* due to the suboptimal design of Hibernate's criteria facility.</b>
|
|
||||||
* @param firstResult the index of the first result object to be retrieved
|
|
||||||
* (numbered from 0)
|
|
||||||
* @param maxResults the maximum number of result objects to retrieve
|
|
||||||
* (or <=0 for no limit)
|
|
||||||
* @return a {@link List} containing 0 or more persistent instances
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.criterion.DetachedCriteria#getExecutableCriteria(org.hibernate.Session)
|
|
||||||
* @see org.hibernate.Criteria#setFirstResult(int)
|
|
||||||
* @see org.hibernate.Criteria#setMaxResults(int)
|
|
||||||
*/
|
|
||||||
List<?> findByCriteria(DetachedCriteria criteria, int firstResult, int maxResults) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a query based on the given example entity object.
|
|
||||||
* @param exampleEntity an instance of the desired entity,
|
|
||||||
* serving as example for "query-by-example"
|
|
||||||
* @return a {@link List} containing 0 or more persistent instances
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.criterion.Example#create(Object)
|
|
||||||
*/
|
|
||||||
<T> List<T> findByExample(T exampleEntity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a query based on the given example entity object.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param exampleEntity an instance of the desired entity,
|
|
||||||
* serving as example for "query-by-example"
|
|
||||||
* @return a {@link List} containing 0 or more persistent instances
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.criterion.Example#create(Object)
|
|
||||||
*/
|
|
||||||
<T> List<T> findByExample(String entityName, T exampleEntity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a query based on a given example entity object.
|
|
||||||
* @param exampleEntity an instance of the desired entity,
|
|
||||||
* serving as example for "query-by-example"
|
|
||||||
* @param firstResult the index of the first result object to be retrieved
|
|
||||||
* (numbered from 0)
|
|
||||||
* @param maxResults the maximum number of result objects to retrieve
|
|
||||||
* (or <=0 for no limit)
|
|
||||||
* @return a {@link List} containing 0 or more persistent instances
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.criterion.Example#create(Object)
|
|
||||||
* @see org.hibernate.Criteria#setFirstResult(int)
|
|
||||||
* @see org.hibernate.Criteria#setMaxResults(int)
|
|
||||||
*/
|
|
||||||
<T> List<T> findByExample(T exampleEntity, int firstResult, int maxResults) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a query based on a given example entity object.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param exampleEntity an instance of the desired entity,
|
|
||||||
* serving as example for "query-by-example"
|
|
||||||
* @param firstResult the index of the first result object to be retrieved
|
|
||||||
* (numbered from 0)
|
|
||||||
* @param maxResults the maximum number of result objects to retrieve
|
|
||||||
* (or <=0 for no limit)
|
|
||||||
* @return a {@link List} containing 0 or more persistent instances
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.criterion.Example#create(Object)
|
|
||||||
* @see org.hibernate.Criteria#setFirstResult(int)
|
|
||||||
* @see org.hibernate.Criteria#setMaxResults(int)
|
|
||||||
*/
|
|
||||||
<T> List<T> findByExample(String entityName, T exampleEntity, int firstResult, int maxResults)
|
|
||||||
throws DataAccessException;
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
// Convenience query methods for iteration and bulk updates/deletes
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a query for persistent instances, binding a number of
|
|
||||||
* values to "?" parameters in the query string.
|
|
||||||
* <p>Returns the results as an {@link Iterator}. Entities returned are
|
|
||||||
* initialized on demand. See the Hibernate API documentation for details.
|
|
||||||
* @param queryString a query expressed in Hibernate's query language
|
|
||||||
* @param values the values of the parameters
|
|
||||||
* @return an {@link Iterator} containing 0 or more persistent instances
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#createQuery
|
|
||||||
* @see org.hibernate.Query#iterate
|
|
||||||
*/
|
|
||||||
Iterator<?> iterate(String queryString, Object... values) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Immediately close an {@link Iterator} created by any of the various
|
|
||||||
* {@code iterate(..)} operations, instead of waiting until the
|
|
||||||
* session is closed or disconnected.
|
|
||||||
* @param it the {@code Iterator} to close
|
|
||||||
* @throws DataAccessException if the {@code Iterator} could not be closed
|
|
||||||
* @see org.hibernate.Hibernate#close
|
|
||||||
*/
|
|
||||||
void closeIterator(Iterator<?> it) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update/delete all objects according to the given query, binding a number of
|
|
||||||
* values to "?" parameters in the query string.
|
|
||||||
* @param queryString an update/delete query expressed in Hibernate's query language
|
|
||||||
* @param values the values of the parameters
|
|
||||||
* @return the number of instances updated/deleted
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#createQuery
|
|
||||||
* @see org.hibernate.Query#executeUpdate
|
|
||||||
*/
|
|
||||||
int bulkUpdate(String queryString, Object... values) throws DataAccessException;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2013 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
||||||
import org.hibernate.StaleObjectStateException;
|
|
||||||
import org.hibernate.StaleStateException;
|
|
||||||
import org.hibernate.dialect.lock.OptimisticEntityLockException;
|
|
||||||
|
|
||||||
import org.springframework.orm.ObjectOptimisticLockingFailureException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate-specific subclass of ObjectOptimisticLockingFailureException.
|
|
||||||
* Converts Hibernate's StaleObjectStateException, StaleStateException
|
|
||||||
* and OptimisticEntityLockException.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class HibernateOptimisticLockingFailureException extends ObjectOptimisticLockingFailureException {
|
|
||||||
|
|
||||||
public HibernateOptimisticLockingFailureException(StaleObjectStateException ex) {
|
|
||||||
super(ex.getEntityName(), ex.getIdentifier(), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HibernateOptimisticLockingFailureException(StaleStateException ex) {
|
|
||||||
super(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HibernateOptimisticLockingFailureException(OptimisticEntityLockException ex) {
|
|
||||||
super(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
||||||
import org.hibernate.QueryException;
|
|
||||||
|
|
||||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate-specific subclass of InvalidDataAccessResourceUsageException,
|
|
||||||
* thrown on invalid HQL query syntax.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class HibernateQueryException extends InvalidDataAccessResourceUsageException {
|
|
||||||
|
|
||||||
public HibernateQueryException(QueryException ex) {
|
|
||||||
super(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the HQL query string that was invalid.
|
|
||||||
*/
|
|
||||||
public String getQueryString() {
|
|
||||||
return ((QueryException) getCause()).getQueryString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
|
|
||||||
import org.springframework.dao.UncategorizedDataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate-specific subclass of UncategorizedDataAccessException,
|
|
||||||
* for Hibernate system errors that do not match any concrete
|
|
||||||
* {@code org.springframework.dao} exceptions.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class HibernateSystemException extends UncategorizedDataAccessException {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new HibernateSystemException,
|
|
||||||
* wrapping an arbitrary HibernateException.
|
|
||||||
* @param cause the HibernateException thrown
|
|
||||||
*/
|
|
||||||
public HibernateSystemException(HibernateException cause) {
|
|
||||||
super(cause != null ? cause.getMessage() : null, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,843 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2016 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
|
|
||||||
import org.hibernate.ConnectionReleaseMode;
|
|
||||||
import org.hibernate.FlushMode;
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.Interceptor;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
import org.hibernate.Transaction;
|
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
|
||||||
import org.hibernate.engine.transaction.spi.TransactionContext;
|
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
|
||||||
import org.springframework.beans.factory.BeanFactoryAware;
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
import org.springframework.dao.DataAccessException;
|
|
||||||
import org.springframework.dao.DataAccessResourceFailureException;
|
|
||||||
import org.springframework.jdbc.datasource.ConnectionHolder;
|
|
||||||
import org.springframework.jdbc.datasource.DataSourceUtils;
|
|
||||||
import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport;
|
|
||||||
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
|
|
||||||
import org.springframework.transaction.CannotCreateTransactionException;
|
|
||||||
import org.springframework.transaction.IllegalTransactionStateException;
|
|
||||||
import org.springframework.transaction.InvalidIsolationLevelException;
|
|
||||||
import org.springframework.transaction.TransactionDefinition;
|
|
||||||
import org.springframework.transaction.TransactionSystemException;
|
|
||||||
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
|
|
||||||
import org.springframework.transaction.support.DefaultTransactionStatus;
|
|
||||||
import org.springframework.transaction.support.ResourceTransactionManager;
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link org.springframework.transaction.PlatformTransactionManager}
|
|
||||||
* implementation for a single Hibernate {@link org.hibernate.SessionFactory}.
|
|
||||||
* Binds a Hibernate Session from the specified factory to the thread,
|
|
||||||
* potentially allowing for one thread-bound Session per factory.
|
|
||||||
* {@code SessionFactory.getCurrentSession()} is required for Hibernate
|
|
||||||
* access code that needs to support this transaction handling mechanism,
|
|
||||||
* with the SessionFactory being configured with {@link SpringSessionContext}.
|
|
||||||
*
|
|
||||||
* <p>Supports custom isolation levels, and timeouts that get applied as
|
|
||||||
* Hibernate transaction timeouts.
|
|
||||||
*
|
|
||||||
* <p>This transaction manager is appropriate for applications that use a single
|
|
||||||
* Hibernate SessionFactory for transactional data access, but it also supports
|
|
||||||
* direct DataSource access within a transaction (i.e. plain JDBC code working
|
|
||||||
* with the same DataSource). This allows for mixing services which access Hibernate
|
|
||||||
* and services which use plain JDBC (without being aware of Hibernate)!
|
|
||||||
* Application code needs to stick to the same simple Connection lookup pattern as
|
|
||||||
* with {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
|
|
||||||
* (i.e. {@link org.springframework.jdbc.datasource.DataSourceUtils#getConnection}
|
|
||||||
* or going through a
|
|
||||||
* {@link org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy}).
|
|
||||||
*
|
|
||||||
* <p>Note: To be able to register a DataSource's Connection for plain JDBC code,
|
|
||||||
* this instance needs to be aware of the DataSource ({@link #setDataSource}).
|
|
||||||
* The given DataSource should obviously match the one used by the given SessionFactory.
|
|
||||||
*
|
|
||||||
* <p>JTA (usually through {@link org.springframework.transaction.jta.JtaTransactionManager})
|
|
||||||
* is necessary for accessing multiple transactional resources within the same
|
|
||||||
* transaction. The DataSource that Hibernate uses needs to be JTA-enabled in
|
|
||||||
* such a scenario (see container setup).
|
|
||||||
*
|
|
||||||
* <p>This transaction manager supports nested transactions via JDBC 3.0 Savepoints.
|
|
||||||
* The {@link #setNestedTransactionAllowed} "nestedTransactionAllowed"} flag defaults
|
|
||||||
* to "false", though, as nested transactions will just apply to the JDBC Connection,
|
|
||||||
* not to the Hibernate Session and its cached entity objects and related context.
|
|
||||||
* You can manually set the flag to "true" if you want to use nested transactions
|
|
||||||
* for JDBC access code which participates in Hibernate transactions (provided that
|
|
||||||
* your JDBC driver supports Savepoints). <i>Note that Hibernate itself does not
|
|
||||||
* support nested transactions! Hence, do not expect Hibernate access code to
|
|
||||||
* semantically participate in a nested transaction.</i>
|
|
||||||
*
|
|
||||||
* <p><b>NOTE: Hibernate 4.2+ is strongly recommended for efficient transaction
|
|
||||||
* management with Spring, in particular for transactional Spring JDBC access.</b>
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
* @see #setSessionFactory
|
|
||||||
* @see #setDataSource
|
|
||||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection
|
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection
|
|
||||||
* @see org.springframework.jdbc.core.JdbcTemplate
|
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
|
|
||||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class HibernateTransactionManager extends AbstractPlatformTransactionManager
|
|
||||||
implements ResourceTransactionManager, BeanFactoryAware, InitializingBean {
|
|
||||||
|
|
||||||
private SessionFactory sessionFactory;
|
|
||||||
|
|
||||||
private DataSource dataSource;
|
|
||||||
|
|
||||||
private boolean autodetectDataSource = true;
|
|
||||||
|
|
||||||
private boolean prepareConnection = true;
|
|
||||||
|
|
||||||
private boolean allowResultAccessAfterCompletion = false;
|
|
||||||
|
|
||||||
private boolean hibernateManagedSession = false;
|
|
||||||
|
|
||||||
private Object entityInterceptor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Just needed for entityInterceptorBeanName.
|
|
||||||
* @see #setEntityInterceptorBeanName
|
|
||||||
*/
|
|
||||||
private BeanFactory beanFactory;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new HibernateTransactionManager instance.
|
|
||||||
* A SessionFactory has to be set to be able to use it.
|
|
||||||
* @see #setSessionFactory
|
|
||||||
*/
|
|
||||||
public HibernateTransactionManager() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new HibernateTransactionManager instance.
|
|
||||||
* @param sessionFactory SessionFactory to manage transactions for
|
|
||||||
*/
|
|
||||||
public HibernateTransactionManager(SessionFactory sessionFactory) {
|
|
||||||
this.sessionFactory = sessionFactory;
|
|
||||||
afterPropertiesSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the SessionFactory that this instance should manage transactions for.
|
|
||||||
*/
|
|
||||||
public void setSessionFactory(SessionFactory sessionFactory) {
|
|
||||||
this.sessionFactory = sessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the SessionFactory that this instance should manage transactions for.
|
|
||||||
*/
|
|
||||||
public SessionFactory getSessionFactory() {
|
|
||||||
return this.sessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the JDBC DataSource that this instance should manage transactions for.
|
|
||||||
* The DataSource should match the one used by the Hibernate SessionFactory:
|
|
||||||
* for example, you could specify the same JNDI DataSource for both.
|
|
||||||
* <p>If the SessionFactory was configured with LocalDataSourceConnectionProvider,
|
|
||||||
* i.e. by Spring's LocalSessionFactoryBean with a specified "dataSource",
|
|
||||||
* the DataSource will be auto-detected: You can still explicitly specify the
|
|
||||||
* DataSource, but you don't need to in this case.
|
|
||||||
* <p>A transactional JDBC Connection for this DataSource will be provided to
|
|
||||||
* application code accessing this DataSource directly via DataSourceUtils
|
|
||||||
* or JdbcTemplate. The Connection will be taken from the Hibernate Session.
|
|
||||||
* <p>The DataSource specified here should be the target DataSource to manage
|
|
||||||
* transactions for, not a TransactionAwareDataSourceProxy. Only data access
|
|
||||||
* code may work with TransactionAwareDataSourceProxy, while the transaction
|
|
||||||
* manager needs to work on the underlying target DataSource. If there's
|
|
||||||
* nevertheless a TransactionAwareDataSourceProxy passed in, it will be
|
|
||||||
* unwrapped to extract its target DataSource.
|
|
||||||
* @see #setAutodetectDataSource
|
|
||||||
* @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
|
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceUtils
|
|
||||||
* @see org.springframework.jdbc.core.JdbcTemplate
|
|
||||||
*/
|
|
||||||
public void setDataSource(DataSource dataSource) {
|
|
||||||
if (dataSource instanceof TransactionAwareDataSourceProxy) {
|
|
||||||
// If we got a TransactionAwareDataSourceProxy, we need to perform transactions
|
|
||||||
// for its underlying target DataSource, else data access code won't see
|
|
||||||
// properly exposed transactions (i.e. transactions for the target DataSource).
|
|
||||||
this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.dataSource = dataSource;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the JDBC DataSource that this instance manages transactions for.
|
|
||||||
*/
|
|
||||||
public DataSource getDataSource() {
|
|
||||||
return this.dataSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether to autodetect a JDBC DataSource used by the Hibernate SessionFactory,
|
|
||||||
* if set via LocalSessionFactoryBean's {@code setDataSource}. Default is "true".
|
|
||||||
* <p>Can be turned off to deliberately ignore an available DataSource, in order
|
|
||||||
* to not expose Hibernate transactions as JDBC transactions for that DataSource.
|
|
||||||
* @see #setDataSource
|
|
||||||
*/
|
|
||||||
public void setAutodetectDataSource(boolean autodetectDataSource) {
|
|
||||||
this.autodetectDataSource = autodetectDataSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether to prepare the underlying JDBC Connection of a transactional
|
|
||||||
* Hibernate Session, that is, whether to apply a transaction-specific
|
|
||||||
* isolation level and/or the transaction's read-only flag to the underlying
|
|
||||||
* JDBC Connection.
|
|
||||||
* <p>Default is "true". If you turn this flag off, the transaction manager
|
|
||||||
* will not support per-transaction isolation levels anymore. It will not
|
|
||||||
* call {@code Connection.setReadOnly(true)} for read-only transactions
|
|
||||||
* anymore either. If this flag is turned off, no cleanup of a JDBC Connection
|
|
||||||
* is required after a transaction, since no Connection settings will get modified.
|
|
||||||
* @see java.sql.Connection#setTransactionIsolation
|
|
||||||
* @see java.sql.Connection#setReadOnly
|
|
||||||
*/
|
|
||||||
public void setPrepareConnection(boolean prepareConnection) {
|
|
||||||
this.prepareConnection = prepareConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether to allow result access after completion, typically via Hibernate's
|
|
||||||
* ScrollableResults mechanism.
|
|
||||||
* <p>Default is "false". Turning this flag on enforces over-commit holdability on the
|
|
||||||
* underlying JDBC Connection (if {@link #prepareConnection "prepareConnection"} is on)
|
|
||||||
* and skips the disconnect-on-completion step.
|
|
||||||
* @since 4.1.2
|
|
||||||
* @see java.sql.Connection#setHoldability
|
|
||||||
* @see ResultSet#HOLD_CURSORS_OVER_COMMIT
|
|
||||||
* @see #disconnectOnCompletion(Session)
|
|
||||||
*/
|
|
||||||
public void setAllowResultAccessAfterCompletion(boolean allowResultAccessAfterCompletion) {
|
|
||||||
this.allowResultAccessAfterCompletion = allowResultAccessAfterCompletion;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether to operate on a Hibernate-managed Session instead of a
|
|
||||||
* Spring-managed Session, that is, whether to obtain the Session through
|
|
||||||
* Hibernate's {@link org.hibernate.SessionFactory#getCurrentSession()}
|
|
||||||
* instead of {@link org.hibernate.SessionFactory#openSession()} (with a Spring
|
|
||||||
* {@link org.springframework.transaction.support.TransactionSynchronizationManager}
|
|
||||||
* check preceding it).
|
|
||||||
* <p>Default is "false", i.e. using a Spring-managed Session: taking the current
|
|
||||||
* thread-bound Session if available (e.g. in an Open-Session-in-View scenario),
|
|
||||||
* creating a new Session for the current transaction otherwise.
|
|
||||||
* <p>Switch this flag to "true" in order to enforce use of a Hibernate-managed Session.
|
|
||||||
* Note that this requires {@link org.hibernate.SessionFactory#getCurrentSession()}
|
|
||||||
* to always return a proper Session when called for a Spring-managed transaction;
|
|
||||||
* transaction begin will fail if the {@code getCurrentSession()} call fails.
|
|
||||||
* <p>This mode will typically be used in combination with a custom Hibernate
|
|
||||||
* {@link org.hibernate.context.spi.CurrentSessionContext} implementation that stores
|
|
||||||
* Sessions in a place other than Spring's TransactionSynchronizationManager.
|
|
||||||
* It may also be used in combination with Spring's Open-Session-in-View support
|
|
||||||
* (using Spring's default {@link SpringSessionContext}), in which case it subtly
|
|
||||||
* differs from the Spring-managed Session mode: The pre-bound Session will <i>not</i>
|
|
||||||
* receive a {@code clear()} call (on rollback) or a {@code disconnect()}
|
|
||||||
* call (on transaction completion) in such a scenario; this is rather left up
|
|
||||||
* to a custom CurrentSessionContext implementation (if desired).
|
|
||||||
*/
|
|
||||||
public void setHibernateManagedSession(boolean hibernateManagedSession) {
|
|
||||||
this.hibernateManagedSession = hibernateManagedSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the bean name of a Hibernate entity interceptor that allows to inspect
|
|
||||||
* and change property values before writing to and reading from the database.
|
|
||||||
* Will get applied to any new Session created by this transaction manager.
|
|
||||||
* <p>Requires the bean factory to be known, to be able to resolve the bean
|
|
||||||
* name to an interceptor instance on session creation. Typically used for
|
|
||||||
* prototype interceptors, i.e. a new interceptor instance per session.
|
|
||||||
* <p>Can also be used for shared interceptor instances, but it is recommended
|
|
||||||
* to set the interceptor reference directly in such a scenario.
|
|
||||||
* @param entityInterceptorBeanName the name of the entity interceptor in
|
|
||||||
* the bean factory
|
|
||||||
* @see #setBeanFactory
|
|
||||||
* @see #setEntityInterceptor
|
|
||||||
*/
|
|
||||||
public void setEntityInterceptorBeanName(String entityInterceptorBeanName) {
|
|
||||||
this.entityInterceptor = entityInterceptorBeanName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a Hibernate entity interceptor that allows to inspect and change
|
|
||||||
* property values before writing to and reading from the database.
|
|
||||||
* Will get applied to any new Session created by this transaction manager.
|
|
||||||
* <p>Such an interceptor can either be set at the SessionFactory level,
|
|
||||||
* i.e. on LocalSessionFactoryBean, or at the Session level, i.e. on
|
|
||||||
* HibernateTransactionManager.
|
|
||||||
* @see LocalSessionFactoryBean#setEntityInterceptor
|
|
||||||
*/
|
|
||||||
public void setEntityInterceptor(Interceptor entityInterceptor) {
|
|
||||||
this.entityInterceptor = entityInterceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the current Hibernate entity interceptor, or {@code null} if none.
|
|
||||||
* Resolves an entity interceptor bean name via the bean factory,
|
|
||||||
* if necessary.
|
|
||||||
* @throws IllegalStateException if bean name specified but no bean factory set
|
|
||||||
* @throws BeansException if bean name resolution via the bean factory failed
|
|
||||||
* @see #setEntityInterceptor
|
|
||||||
* @see #setEntityInterceptorBeanName
|
|
||||||
* @see #setBeanFactory
|
|
||||||
*/
|
|
||||||
public Interceptor getEntityInterceptor() throws IllegalStateException, BeansException {
|
|
||||||
if (this.entityInterceptor instanceof Interceptor) {
|
|
||||||
return (Interceptor) entityInterceptor;
|
|
||||||
}
|
|
||||||
else if (this.entityInterceptor instanceof String) {
|
|
||||||
if (this.beanFactory == null) {
|
|
||||||
throw new IllegalStateException("Cannot get entity interceptor via bean name if no bean factory set");
|
|
||||||
}
|
|
||||||
String beanName = (String) this.entityInterceptor;
|
|
||||||
return this.beanFactory.getBean(beanName, Interceptor.class);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The bean factory just needs to be known for resolving entity interceptor
|
|
||||||
* bean names. It does not need to be set for any other mode of operation.
|
|
||||||
* @see #setEntityInterceptorBeanName
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void setBeanFactory(BeanFactory beanFactory) {
|
|
||||||
this.beanFactory = beanFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterPropertiesSet() {
|
|
||||||
if (getSessionFactory() == null) {
|
|
||||||
throw new IllegalArgumentException("Property 'sessionFactory' is required");
|
|
||||||
}
|
|
||||||
if (this.entityInterceptor instanceof String && this.beanFactory == null) {
|
|
||||||
throw new IllegalArgumentException("Property 'beanFactory' is required for 'entityInterceptorBeanName'");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for SessionFactory's DataSource.
|
|
||||||
if (this.autodetectDataSource && getDataSource() == null) {
|
|
||||||
DataSource sfds = SessionFactoryUtils.getDataSource(getSessionFactory());
|
|
||||||
if (sfds != null) {
|
|
||||||
// Use the SessionFactory's DataSource for exposing transactions to JDBC code.
|
|
||||||
if (logger.isInfoEnabled()) {
|
|
||||||
logger.info("Using DataSource [" + sfds +
|
|
||||||
"] of Hibernate SessionFactory for HibernateTransactionManager");
|
|
||||||
}
|
|
||||||
setDataSource(sfds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getResourceFactory() {
|
|
||||||
return getSessionFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Object doGetTransaction() {
|
|
||||||
HibernateTransactionObject txObject = new HibernateTransactionObject();
|
|
||||||
txObject.setSavepointAllowed(isNestedTransactionAllowed());
|
|
||||||
|
|
||||||
SessionHolder sessionHolder =
|
|
||||||
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
|
|
||||||
if (sessionHolder != null) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Found thread-bound Session [" + sessionHolder.getSession() + "] for Hibernate transaction");
|
|
||||||
}
|
|
||||||
txObject.setSessionHolder(sessionHolder);
|
|
||||||
}
|
|
||||||
else if (this.hibernateManagedSession) {
|
|
||||||
try {
|
|
||||||
Session session = this.sessionFactory.getCurrentSession();
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Found Hibernate-managed Session [" + session + "] for Spring-managed transaction");
|
|
||||||
}
|
|
||||||
txObject.setExistingSession(session);
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
throw new DataAccessResourceFailureException(
|
|
||||||
"Could not obtain Hibernate-managed Session for Spring-managed transaction", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getDataSource() != null) {
|
|
||||||
ConnectionHolder conHolder = (ConnectionHolder)
|
|
||||||
TransactionSynchronizationManager.getResource(getDataSource());
|
|
||||||
txObject.setConnectionHolder(conHolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
return txObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isExistingTransaction(Object transaction) {
|
|
||||||
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
|
|
||||||
return (txObject.hasSpringManagedTransaction() ||
|
|
||||||
(this.hibernateManagedSession && txObject.hasHibernateManagedTransaction()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doBegin(Object transaction, TransactionDefinition definition) {
|
|
||||||
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
|
|
||||||
|
|
||||||
if (txObject.hasConnectionHolder() && !txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
|
|
||||||
throw new IllegalTransactionStateException(
|
|
||||||
"Pre-bound JDBC Connection found! HibernateTransactionManager does not support " +
|
|
||||||
"running within DataSourceTransactionManager if told to manage the DataSource itself. " +
|
|
||||||
"It is recommended to use a single HibernateTransactionManager for all transactions " +
|
|
||||||
"on a single DataSource, no matter whether Hibernate or JDBC access.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Session session = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
|
|
||||||
Interceptor entityInterceptor = getEntityInterceptor();
|
|
||||||
Session newSession = (entityInterceptor != null ?
|
|
||||||
getSessionFactory().withOptions().interceptor(entityInterceptor).openSession() :
|
|
||||||
getSessionFactory().openSession());
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Opened new Session [" + newSession + "] for Hibernate transaction");
|
|
||||||
}
|
|
||||||
txObject.setSession(newSession);
|
|
||||||
}
|
|
||||||
|
|
||||||
session = txObject.getSessionHolder().getSession();
|
|
||||||
|
|
||||||
if (this.prepareConnection && isSameConnectionForEntireSession(session)) {
|
|
||||||
// We're allowed to change the transaction settings of the JDBC Connection.
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Preparing JDBC Connection of Hibernate Session [" + session + "]");
|
|
||||||
}
|
|
||||||
Connection con = ((SessionImplementor) session).connection();
|
|
||||||
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
|
|
||||||
txObject.setPreviousIsolationLevel(previousIsolationLevel);
|
|
||||||
if (this.allowResultAccessAfterCompletion && !txObject.isNewSession()) {
|
|
||||||
int currentHoldability = con.getHoldability();
|
|
||||||
if (currentHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
|
|
||||||
txObject.setPreviousHoldability(currentHoldability);
|
|
||||||
con.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Not allowed to change the transaction settings of the JDBC Connection.
|
|
||||||
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
|
|
||||||
// We should set a specific isolation level but are not allowed to...
|
|
||||||
throw new InvalidIsolationLevelException(
|
|
||||||
"HibernateTransactionManager is not allowed to support custom isolation levels: " +
|
|
||||||
"make sure that its 'prepareConnection' flag is on (the default) and that the " +
|
|
||||||
"Hibernate connection release mode is set to 'on_close' (the default for JDBC).");
|
|
||||||
}
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Not preparing JDBC Connection of Hibernate Session [" + session + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (definition.isReadOnly() && txObject.isNewSession()) {
|
|
||||||
// Just set to MANUAL in case of a new Session for this transaction.
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!definition.isReadOnly() && !txObject.isNewSession()) {
|
|
||||||
// We need AUTO or COMMIT for a non-read-only transaction.
|
|
||||||
FlushMode flushMode = session.getFlushMode();
|
|
||||||
if (FlushMode.MANUAL.equals(flushMode)) {
|
|
||||||
session.setFlushMode(FlushMode.AUTO);
|
|
||||||
txObject.getSessionHolder().setPreviousFlushMode(flushMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Transaction hibTx;
|
|
||||||
|
|
||||||
// Register transaction timeout.
|
|
||||||
int timeout = determineTimeout(definition);
|
|
||||||
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
|
|
||||||
// Use Hibernate's own transaction timeout mechanism on Hibernate 3.1+
|
|
||||||
// Applies to all statements, also to inserts, updates and deletes!
|
|
||||||
hibTx = session.getTransaction();
|
|
||||||
hibTx.setTimeout(timeout);
|
|
||||||
hibTx.begin();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Open a plain Hibernate transaction without specified timeout.
|
|
||||||
hibTx = session.beginTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the Hibernate transaction to the session holder.
|
|
||||||
txObject.getSessionHolder().setTransaction(hibTx);
|
|
||||||
|
|
||||||
// Register the Hibernate Session's JDBC Connection for the DataSource, if set.
|
|
||||||
if (getDataSource() != null) {
|
|
||||||
Connection con = ((SessionImplementor) session).connection();
|
|
||||||
ConnectionHolder conHolder = new ConnectionHolder(con);
|
|
||||||
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
|
|
||||||
conHolder.setTimeoutInSeconds(timeout);
|
|
||||||
}
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Exposing Hibernate transaction as JDBC transaction [" + con + "]");
|
|
||||||
}
|
|
||||||
TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);
|
|
||||||
txObject.setConnectionHolder(conHolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind the session holder to the thread.
|
|
||||||
if (txObject.isNewSessionHolder()) {
|
|
||||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder());
|
|
||||||
}
|
|
||||||
txObject.getSessionHolder().setSynchronizedWithTransaction(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Throwable ex) {
|
|
||||||
if (txObject.isNewSession()) {
|
|
||||||
try {
|
|
||||||
if (session.getTransaction().isActive()) {
|
|
||||||
session.getTransaction().rollback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Throwable ex2) {
|
|
||||||
logger.debug("Could not rollback Session after failed transaction begin", ex);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
SessionFactoryUtils.closeSession(session);
|
|
||||||
txObject.setSessionHolder(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Object doSuspend(Object transaction) {
|
|
||||||
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
|
|
||||||
txObject.setSessionHolder(null);
|
|
||||||
SessionHolder sessionHolder =
|
|
||||||
(SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
|
||||||
txObject.setConnectionHolder(null);
|
|
||||||
ConnectionHolder connectionHolder = null;
|
|
||||||
if (getDataSource() != null) {
|
|
||||||
connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.unbindResource(getDataSource());
|
|
||||||
}
|
|
||||||
return new SuspendedResourcesHolder(sessionHolder, connectionHolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doResume(Object transaction, Object suspendedResources) {
|
|
||||||
SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources;
|
|
||||||
if (TransactionSynchronizationManager.hasResource(getSessionFactory())) {
|
|
||||||
// From non-transactional code running in active transaction synchronization
|
|
||||||
// -> can be safely removed, will be closed on transaction completion.
|
|
||||||
TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
|
||||||
}
|
|
||||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), resourcesHolder.getSessionHolder());
|
|
||||||
if (getDataSource() != null) {
|
|
||||||
TransactionSynchronizationManager.bindResource(getDataSource(), resourcesHolder.getConnectionHolder());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doCommit(DefaultTransactionStatus status) {
|
|
||||||
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
|
|
||||||
if (status.isDebug()) {
|
|
||||||
logger.debug("Committing Hibernate transaction on Session [" +
|
|
||||||
txObject.getSessionHolder().getSession() + "]");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
txObject.getSessionHolder().getTransaction().commit();
|
|
||||||
}
|
|
||||||
catch (org.hibernate.TransactionException ex) {
|
|
||||||
// assumably from commit call to the underlying JDBC connection
|
|
||||||
throw new TransactionSystemException("Could not commit Hibernate transaction", ex);
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
// assumably failed to flush changes to database
|
|
||||||
throw convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doRollback(DefaultTransactionStatus status) {
|
|
||||||
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
|
|
||||||
if (status.isDebug()) {
|
|
||||||
logger.debug("Rolling back Hibernate transaction on Session [" +
|
|
||||||
txObject.getSessionHolder().getSession() + "]");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
txObject.getSessionHolder().getTransaction().rollback();
|
|
||||||
}
|
|
||||||
catch (org.hibernate.TransactionException ex) {
|
|
||||||
throw new TransactionSystemException("Could not roll back Hibernate transaction", ex);
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
// Shouldn't really happen, as a rollback doesn't cause a flush.
|
|
||||||
throw convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if (!txObject.isNewSession() && !this.hibernateManagedSession) {
|
|
||||||
// Clear all pending inserts/updates/deletes in the Session.
|
|
||||||
// Necessary for pre-bound Sessions, to avoid inconsistent state.
|
|
||||||
txObject.getSessionHolder().getSession().clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doSetRollbackOnly(DefaultTransactionStatus status) {
|
|
||||||
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
|
|
||||||
if (status.isDebug()) {
|
|
||||||
logger.debug("Setting Hibernate transaction on Session [" +
|
|
||||||
txObject.getSessionHolder().getSession() + "] rollback-only");
|
|
||||||
}
|
|
||||||
txObject.setRollbackOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doCleanupAfterCompletion(Object transaction) {
|
|
||||||
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
|
|
||||||
|
|
||||||
// Remove the session holder from the thread.
|
|
||||||
if (txObject.isNewSessionHolder()) {
|
|
||||||
TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the JDBC connection holder from the thread, if exposed.
|
|
||||||
if (getDataSource() != null) {
|
|
||||||
TransactionSynchronizationManager.unbindResource(getDataSource());
|
|
||||||
}
|
|
||||||
|
|
||||||
Session session = txObject.getSessionHolder().getSession();
|
|
||||||
if (this.prepareConnection && session.isConnected() && isSameConnectionForEntireSession(session)) {
|
|
||||||
// We're running with connection release mode "on_close": We're able to reset
|
|
||||||
// the isolation level and/or read-only flag of the JDBC Connection here.
|
|
||||||
// Else, we need to rely on the connection pool to perform proper cleanup.
|
|
||||||
try {
|
|
||||||
Connection con = ((SessionImplementor) session).connection();
|
|
||||||
Integer previousHoldability = txObject.getPreviousHoldability();
|
|
||||||
if (previousHoldability != null) {
|
|
||||||
con.setHoldability(previousHoldability);
|
|
||||||
}
|
|
||||||
DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
logger.debug("Could not access JDBC Connection of Hibernate Session", ex);
|
|
||||||
}
|
|
||||||
catch (Throwable ex) {
|
|
||||||
logger.debug("Could not reset JDBC Connection after transaction", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (txObject.isNewSession()) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Closing Hibernate Session [" + session + "] after transaction");
|
|
||||||
}
|
|
||||||
SessionFactoryUtils.closeSession(session);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Not closing pre-bound Hibernate Session [" + session + "] after transaction");
|
|
||||||
}
|
|
||||||
if (txObject.getSessionHolder().getPreviousFlushMode() != null) {
|
|
||||||
session.setFlushMode(txObject.getSessionHolder().getPreviousFlushMode());
|
|
||||||
}
|
|
||||||
if (!this.allowResultAccessAfterCompletion && !this.hibernateManagedSession) {
|
|
||||||
disconnectOnCompletion(session);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
txObject.getSessionHolder().clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disconnect a pre-existing Hibernate Session on transaction completion,
|
|
||||||
* returning its database connection but preserving its entity state.
|
|
||||||
* <p>The default implementation simply calls {@link Session#disconnect()}.
|
|
||||||
* Subclasses may override this with a no-op or with fine-tuned disconnection logic.
|
|
||||||
* @param session the Hibernate Session to disconnect
|
|
||||||
* @since 4.1.2
|
|
||||||
* @see org.hibernate.Session#disconnect()
|
|
||||||
*/
|
|
||||||
protected void disconnectOnCompletion(Session session) {
|
|
||||||
session.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return whether the given Hibernate Session will always hold the same
|
|
||||||
* JDBC Connection. This is used to check whether the transaction manager
|
|
||||||
* can safely prepare and clean up the JDBC Connection used for a transaction.
|
|
||||||
* <p>The default implementation checks the Session's connection release mode
|
|
||||||
* to be "on_close".
|
|
||||||
* @param session the Hibernate Session to check
|
|
||||||
* @see org.hibernate.engine.transaction.spi.TransactionContext#getConnectionReleaseMode()
|
|
||||||
* @see org.hibernate.ConnectionReleaseMode#ON_CLOSE
|
|
||||||
*/
|
|
||||||
protected boolean isSameConnectionForEntireSession(Session session) {
|
|
||||||
if (!(session instanceof TransactionContext)) {
|
|
||||||
// The best we can do is to assume we're safe.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
ConnectionReleaseMode releaseMode = ((TransactionContext) session).getConnectionReleaseMode();
|
|
||||||
return ConnectionReleaseMode.ON_CLOSE.equals(releaseMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the given HibernateException to an appropriate exception
|
|
||||||
* from the {@code org.springframework.dao} hierarchy.
|
|
||||||
* <p>Will automatically apply a specified SQLExceptionTranslator to a
|
|
||||||
* Hibernate JDBCException, else rely on Hibernate's default translation.
|
|
||||||
* @param ex HibernateException that occurred
|
|
||||||
* @return a corresponding DataAccessException
|
|
||||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
|
||||||
*/
|
|
||||||
protected DataAccessException convertHibernateAccessException(HibernateException ex) {
|
|
||||||
return SessionFactoryUtils.convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate transaction object, representing a SessionHolder.
|
|
||||||
* Used as transaction object by HibernateTransactionManager.
|
|
||||||
*/
|
|
||||||
private class HibernateTransactionObject extends JdbcTransactionObjectSupport {
|
|
||||||
|
|
||||||
private SessionHolder sessionHolder;
|
|
||||||
|
|
||||||
private boolean newSessionHolder;
|
|
||||||
|
|
||||||
private boolean newSession;
|
|
||||||
|
|
||||||
private Integer previousHoldability;
|
|
||||||
|
|
||||||
public void setSession(Session session) {
|
|
||||||
this.sessionHolder = new SessionHolder(session);
|
|
||||||
this.newSessionHolder = true;
|
|
||||||
this.newSession = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExistingSession(Session session) {
|
|
||||||
this.sessionHolder = new SessionHolder(session);
|
|
||||||
this.newSessionHolder = true;
|
|
||||||
this.newSession = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSessionHolder(SessionHolder sessionHolder) {
|
|
||||||
this.sessionHolder = sessionHolder;
|
|
||||||
this.newSessionHolder = false;
|
|
||||||
this.newSession = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SessionHolder getSessionHolder() {
|
|
||||||
return this.sessionHolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNewSessionHolder() {
|
|
||||||
return this.newSessionHolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNewSession() {
|
|
||||||
return this.newSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPreviousHoldability(Integer previousHoldability) {
|
|
||||||
this.previousHoldability = previousHoldability;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getPreviousHoldability() {
|
|
||||||
return this.previousHoldability;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasSpringManagedTransaction() {
|
|
||||||
return (this.sessionHolder != null && this.sessionHolder.getTransaction() != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasHibernateManagedTransaction() {
|
|
||||||
return (this.sessionHolder != null && this.sessionHolder.getSession().getTransaction().isActive());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRollbackOnly() {
|
|
||||||
this.sessionHolder.setRollbackOnly();
|
|
||||||
if (hasConnectionHolder()) {
|
|
||||||
getConnectionHolder().setRollbackOnly();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRollbackOnly() {
|
|
||||||
return this.sessionHolder.isRollbackOnly() ||
|
|
||||||
(hasConnectionHolder() && getConnectionHolder().isRollbackOnly());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void flush() {
|
|
||||||
try {
|
|
||||||
this.sessionHolder.getSession().flush();
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
throw convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holder for suspended resources.
|
|
||||||
* Used internally by {@code doSuspend} and {@code doResume}.
|
|
||||||
*/
|
|
||||||
private static class SuspendedResourcesHolder {
|
|
||||||
|
|
||||||
private final SessionHolder sessionHolder;
|
|
||||||
|
|
||||||
private final ConnectionHolder connectionHolder;
|
|
||||||
|
|
||||||
private SuspendedResourcesHolder(SessionHolder sessionHolder, ConnectionHolder conHolder) {
|
|
||||||
this.sessionHolder = sessionHolder;
|
|
||||||
this.connectionHolder = conHolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
private SessionHolder getSessionHolder() {
|
|
||||||
return this.sessionHolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ConnectionHolder getConnectionHolder() {
|
|
||||||
return this.connectionHolder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,491 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Properties;
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
|
|
||||||
import org.hibernate.Interceptor;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
import org.hibernate.cache.spi.RegionFactory;
|
|
||||||
import org.hibernate.cfg.Configuration;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.DisposableBean;
|
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
import org.springframework.context.ResourceLoaderAware;
|
|
||||||
import org.springframework.core.io.ClassPathResource;
|
|
||||||
import org.springframework.core.io.Resource;
|
|
||||||
import org.springframework.core.io.ResourceLoader;
|
|
||||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
|
||||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
|
||||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
|
||||||
import org.springframework.core.type.filter.TypeFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link org.springframework.beans.factory.FactoryBean} that creates a Hibernate
|
|
||||||
* {@link org.hibernate.SessionFactory}. This is the usual way to set up a shared
|
|
||||||
* Hibernate SessionFactory in a Spring application context; the SessionFactory can
|
|
||||||
* then be passed to Hibernate-based data access objects via dependency injection.
|
|
||||||
*
|
|
||||||
* <p><b>This variant of LocalSessionFactoryBean requires Hibernate 4.0 or higher.</b>
|
|
||||||
* As of Spring 4.0, it is compatible with (the quite refactored) Hibernate 4.3 as well.
|
|
||||||
* We recommend using the latest Hibernate 4.2.x or 4.3.x version, depending on whether
|
|
||||||
* you need to remain JPA 2.0 compatible at runtime (Hibernate 4.2) or can upgrade to
|
|
||||||
* JPA 2.1 (Hibernate 4.3).
|
|
||||||
*
|
|
||||||
* <p>This class is similar in role to the same-named class in the {@code orm.hibernate3}
|
|
||||||
* package. However, in practice, it is closer to {@code AnnotationSessionFactoryBean}
|
|
||||||
* since its core purpose is to bootstrap a {@code SessionFactory} from package scanning.
|
|
||||||
*
|
|
||||||
* <p><b>NOTE:</b> To set up Hibernate 4 for Spring-driven JTA transactions, make
|
|
||||||
* sure to either specify the {@link #setJtaTransactionManager "jtaTransactionManager"}
|
|
||||||
* bean property or to set the "hibernate.transaction.factory_class" property to
|
|
||||||
* {@link org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory}.
|
|
||||||
* Otherwise, Hibernate's smart flushing mechanism won't work properly.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
* @see #setDataSource
|
|
||||||
* @see #setPackagesToScan
|
|
||||||
* @see LocalSessionFactoryBuilder
|
|
||||||
*/
|
|
||||||
public class LocalSessionFactoryBean extends HibernateExceptionTranslator
|
|
||||||
implements FactoryBean<SessionFactory>, ResourceLoaderAware, InitializingBean, DisposableBean {
|
|
||||||
|
|
||||||
private DataSource dataSource;
|
|
||||||
|
|
||||||
private Resource[] configLocations;
|
|
||||||
|
|
||||||
private String[] mappingResources;
|
|
||||||
|
|
||||||
private Resource[] mappingLocations;
|
|
||||||
|
|
||||||
private Resource[] cacheableMappingLocations;
|
|
||||||
|
|
||||||
private Resource[] mappingJarLocations;
|
|
||||||
|
|
||||||
private Resource[] mappingDirectoryLocations;
|
|
||||||
|
|
||||||
private Interceptor entityInterceptor;
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
private org.hibernate.cfg.NamingStrategy namingStrategy;
|
|
||||||
|
|
||||||
private Object jtaTransactionManager;
|
|
||||||
|
|
||||||
private Object multiTenantConnectionProvider;
|
|
||||||
|
|
||||||
private Object currentTenantIdentifierResolver;
|
|
||||||
|
|
||||||
private RegionFactory cacheRegionFactory;
|
|
||||||
|
|
||||||
private TypeFilter[] entityTypeFilters;
|
|
||||||
|
|
||||||
private Properties hibernateProperties;
|
|
||||||
|
|
||||||
private Class<?>[] annotatedClasses;
|
|
||||||
|
|
||||||
private String[] annotatedPackages;
|
|
||||||
|
|
||||||
private String[] packagesToScan;
|
|
||||||
|
|
||||||
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
|
|
||||||
|
|
||||||
private Configuration configuration;
|
|
||||||
|
|
||||||
private SessionFactory sessionFactory;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the DataSource to be used by the SessionFactory.
|
|
||||||
* If set, this will override corresponding settings in Hibernate properties.
|
|
||||||
* <p>If this is set, the Hibernate settings should not define
|
|
||||||
* a connection provider to avoid meaningless double configuration.
|
|
||||||
*/
|
|
||||||
public void setDataSource(DataSource dataSource) {
|
|
||||||
this.dataSource = dataSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the location of a single Hibernate XML config file, for example as
|
|
||||||
* classpath resource "classpath:hibernate.cfg.xml".
|
|
||||||
* <p>Note: Can be omitted when all necessary properties and mapping
|
|
||||||
* resources are specified locally via this bean.
|
|
||||||
* @see org.hibernate.cfg.Configuration#configure(java.net.URL)
|
|
||||||
*/
|
|
||||||
public void setConfigLocation(Resource configLocation) {
|
|
||||||
this.configLocations = new Resource[] {configLocation};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the locations of multiple Hibernate XML config files, for example as
|
|
||||||
* classpath resources "classpath:hibernate.cfg.xml,classpath:extension.cfg.xml".
|
|
||||||
* <p>Note: Can be omitted when all necessary properties and mapping
|
|
||||||
* resources are specified locally via this bean.
|
|
||||||
* @see org.hibernate.cfg.Configuration#configure(java.net.URL)
|
|
||||||
*/
|
|
||||||
public void setConfigLocations(Resource... configLocations) {
|
|
||||||
this.configLocations = configLocations;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set Hibernate mapping resources to be found in the class path,
|
|
||||||
* like "example.hbm.xml" or "mypackage/example.hbm.xml".
|
|
||||||
* Analogous to mapping entries in a Hibernate XML config file.
|
|
||||||
* Alternative to the more generic setMappingLocations method.
|
|
||||||
* <p>Can be used to add to mappings from a Hibernate XML config file,
|
|
||||||
* or to specify all mappings locally.
|
|
||||||
* @see #setMappingLocations
|
|
||||||
* @see org.hibernate.cfg.Configuration#addResource
|
|
||||||
*/
|
|
||||||
public void setMappingResources(String... mappingResources) {
|
|
||||||
this.mappingResources = mappingResources;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set locations of Hibernate mapping files, for example as classpath
|
|
||||||
* resource "classpath:example.hbm.xml". Supports any resource location
|
|
||||||
* via Spring's resource abstraction, for example relative paths like
|
|
||||||
* "WEB-INF/mappings/example.hbm.xml" when running in an application context.
|
|
||||||
* <p>Can be used to add to mappings from a Hibernate XML config file,
|
|
||||||
* or to specify all mappings locally.
|
|
||||||
* @see org.hibernate.cfg.Configuration#addInputStream
|
|
||||||
*/
|
|
||||||
public void setMappingLocations(Resource... mappingLocations) {
|
|
||||||
this.mappingLocations = mappingLocations;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set locations of cacheable Hibernate mapping files, for example as web app
|
|
||||||
* resource "/WEB-INF/mapping/example.hbm.xml". Supports any resource location
|
|
||||||
* via Spring's resource abstraction, as long as the resource can be resolved
|
|
||||||
* in the file system.
|
|
||||||
* <p>Can be used to add to mappings from a Hibernate XML config file,
|
|
||||||
* or to specify all mappings locally.
|
|
||||||
* @see org.hibernate.cfg.Configuration#addCacheableFile(java.io.File)
|
|
||||||
*/
|
|
||||||
public void setCacheableMappingLocations(Resource... cacheableMappingLocations) {
|
|
||||||
this.cacheableMappingLocations = cacheableMappingLocations;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set locations of jar files that contain Hibernate mapping resources,
|
|
||||||
* like "WEB-INF/lib/example.hbm.jar".
|
|
||||||
* <p>Can be used to add to mappings from a Hibernate XML config file,
|
|
||||||
* or to specify all mappings locally.
|
|
||||||
* @see org.hibernate.cfg.Configuration#addJar(java.io.File)
|
|
||||||
*/
|
|
||||||
public void setMappingJarLocations(Resource... mappingJarLocations) {
|
|
||||||
this.mappingJarLocations = mappingJarLocations;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set locations of directories that contain Hibernate mapping resources,
|
|
||||||
* like "WEB-INF/mappings".
|
|
||||||
* <p>Can be used to add to mappings from a Hibernate XML config file,
|
|
||||||
* or to specify all mappings locally.
|
|
||||||
* @see org.hibernate.cfg.Configuration#addDirectory(java.io.File)
|
|
||||||
*/
|
|
||||||
public void setMappingDirectoryLocations(Resource... mappingDirectoryLocations) {
|
|
||||||
this.mappingDirectoryLocations = mappingDirectoryLocations;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a Hibernate entity interceptor that allows to inspect and change
|
|
||||||
* property values before writing to and reading from the database.
|
|
||||||
* Will get applied to any new Session created by this factory.
|
|
||||||
* @see org.hibernate.cfg.Configuration#setInterceptor
|
|
||||||
*/
|
|
||||||
public void setEntityInterceptor(Interceptor entityInterceptor) {
|
|
||||||
this.entityInterceptor = entityInterceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a Hibernate NamingStrategy for the SessionFactory, determining the
|
|
||||||
* physical column and table names given the info in the mapping document.
|
|
||||||
* @see org.hibernate.cfg.Configuration#setNamingStrategy
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public void setNamingStrategy(org.hibernate.cfg.NamingStrategy namingStrategy) {
|
|
||||||
this.namingStrategy = namingStrategy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Spring {@link org.springframework.transaction.jta.JtaTransactionManager}
|
|
||||||
* or the JTA {@link javax.transaction.TransactionManager} to be used with Hibernate,
|
|
||||||
* if any. Implicitly sets up {@code JtaPlatform} and {@code CMTTransactionStrategy}.
|
|
||||||
* @see LocalSessionFactoryBuilder#setJtaTransactionManager
|
|
||||||
*/
|
|
||||||
public void setJtaTransactionManager(Object jtaTransactionManager) {
|
|
||||||
this.jtaTransactionManager = jtaTransactionManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a Hibernate 4.1/4.2/4.3 {@code MultiTenantConnectionProvider} to be passed
|
|
||||||
* on to the SessionFactory: as an instance, a Class, or a String class name.
|
|
||||||
* <p>Note that the package location of the {@code MultiTenantConnectionProvider}
|
|
||||||
* interface changed between Hibernate 4.2 and 4.3. This method accepts both variants.
|
|
||||||
* @since 4.0
|
|
||||||
* @see LocalSessionFactoryBuilder#setMultiTenantConnectionProvider
|
|
||||||
*/
|
|
||||||
public void setMultiTenantConnectionProvider(Object multiTenantConnectionProvider) {
|
|
||||||
this.multiTenantConnectionProvider = multiTenantConnectionProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a Hibernate 4.1/4.2/4.3 {@code CurrentTenantIdentifierResolver} to be passed
|
|
||||||
* on to the SessionFactory: as an instance, a Class, or a String class name.
|
|
||||||
* @since 4.0
|
|
||||||
* @see LocalSessionFactoryBuilder#setCurrentTenantIdentifierResolver
|
|
||||||
*/
|
|
||||||
public void setCurrentTenantIdentifierResolver(Object currentTenantIdentifierResolver) {
|
|
||||||
this.currentTenantIdentifierResolver = currentTenantIdentifierResolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Hibernate RegionFactory to use for the SessionFactory.
|
|
||||||
* Allows for using a Spring-managed RegionFactory instance.
|
|
||||||
* <p>Note: If this is set, the Hibernate settings should not define a
|
|
||||||
* cache provider to avoid meaningless double configuration.
|
|
||||||
* @since 4.0
|
|
||||||
* @see org.hibernate.cache.spi.RegionFactory
|
|
||||||
* @see LocalSessionFactoryBuilder#setCacheRegionFactory
|
|
||||||
*/
|
|
||||||
public void setCacheRegionFactory(RegionFactory cacheRegionFactory) {
|
|
||||||
this.cacheRegionFactory = cacheRegionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify custom type filters for Spring-based scanning for entity classes.
|
|
||||||
* <p>Default is to search all specified packages for classes annotated with
|
|
||||||
* {@code @javax.persistence.Entity}, {@code @javax.persistence.Embeddable}
|
|
||||||
* or {@code @javax.persistence.MappedSuperclass}.
|
|
||||||
* @since 4.1
|
|
||||||
* @see #setPackagesToScan
|
|
||||||
*/
|
|
||||||
public void setEntityTypeFilters(TypeFilter... entityTypeFilters) {
|
|
||||||
this.entityTypeFilters = entityTypeFilters;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set Hibernate properties, such as "hibernate.dialect".
|
|
||||||
* <p>Note: Do not specify a transaction provider here when using
|
|
||||||
* Spring-driven transactions. It is also advisable to omit connection
|
|
||||||
* provider settings and use a Spring-set DataSource instead.
|
|
||||||
* @see #setDataSource
|
|
||||||
*/
|
|
||||||
public void setHibernateProperties(Properties hibernateProperties) {
|
|
||||||
this.hibernateProperties = hibernateProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the Hibernate properties, if any. Mainly available for
|
|
||||||
* configuration through property paths that specify individual keys.
|
|
||||||
*/
|
|
||||||
public Properties getHibernateProperties() {
|
|
||||||
if (this.hibernateProperties == null) {
|
|
||||||
this.hibernateProperties = new Properties();
|
|
||||||
}
|
|
||||||
return this.hibernateProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify annotated entity classes to register with this Hibernate SessionFactory.
|
|
||||||
* @see org.hibernate.cfg.Configuration#addAnnotatedClass(Class)
|
|
||||||
*/
|
|
||||||
public void setAnnotatedClasses(Class<?>... annotatedClasses) {
|
|
||||||
this.annotatedClasses = annotatedClasses;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the names of annotated packages, for which package-level
|
|
||||||
* annotation metadata will be read.
|
|
||||||
* @see org.hibernate.cfg.Configuration#addPackage(String)
|
|
||||||
*/
|
|
||||||
public void setAnnotatedPackages(String... annotatedPackages) {
|
|
||||||
this.annotatedPackages = annotatedPackages;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify packages to search for autodetection of your entity classes in the
|
|
||||||
* classpath. This is analogous to Spring's component-scan feature
|
|
||||||
* ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}).
|
|
||||||
*/
|
|
||||||
public void setPackagesToScan(String... packagesToScan) {
|
|
||||||
this.packagesToScan = packagesToScan;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
|
||||||
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterPropertiesSet() throws IOException {
|
|
||||||
LocalSessionFactoryBuilder sfb = new LocalSessionFactoryBuilder(this.dataSource, this.resourcePatternResolver);
|
|
||||||
|
|
||||||
if (this.configLocations != null) {
|
|
||||||
for (Resource resource : this.configLocations) {
|
|
||||||
// Load Hibernate configuration from given location.
|
|
||||||
sfb.configure(resource.getURL());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.mappingResources != null) {
|
|
||||||
// Register given Hibernate mapping definitions, contained in resource files.
|
|
||||||
for (String mapping : this.mappingResources) {
|
|
||||||
Resource mr = new ClassPathResource(mapping.trim(), this.resourcePatternResolver.getClassLoader());
|
|
||||||
sfb.addInputStream(mr.getInputStream());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.mappingLocations != null) {
|
|
||||||
// Register given Hibernate mapping definitions, contained in resource files.
|
|
||||||
for (Resource resource : this.mappingLocations) {
|
|
||||||
sfb.addInputStream(resource.getInputStream());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.cacheableMappingLocations != null) {
|
|
||||||
// Register given cacheable Hibernate mapping definitions, read from the file system.
|
|
||||||
for (Resource resource : this.cacheableMappingLocations) {
|
|
||||||
sfb.addCacheableFile(resource.getFile());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.mappingJarLocations != null) {
|
|
||||||
// Register given Hibernate mapping definitions, contained in jar files.
|
|
||||||
for (Resource resource : this.mappingJarLocations) {
|
|
||||||
sfb.addJar(resource.getFile());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.mappingDirectoryLocations != null) {
|
|
||||||
// Register all Hibernate mapping definitions in the given directories.
|
|
||||||
for (Resource resource : this.mappingDirectoryLocations) {
|
|
||||||
File file = resource.getFile();
|
|
||||||
if (!file.isDirectory()) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Mapping directory location [" + resource + "] does not denote a directory");
|
|
||||||
}
|
|
||||||
sfb.addDirectory(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.entityInterceptor != null) {
|
|
||||||
sfb.setInterceptor(this.entityInterceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.namingStrategy != null) {
|
|
||||||
sfb.setNamingStrategy(this.namingStrategy);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.jtaTransactionManager != null) {
|
|
||||||
sfb.setJtaTransactionManager(this.jtaTransactionManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.multiTenantConnectionProvider != null) {
|
|
||||||
sfb.setMultiTenantConnectionProvider(this.multiTenantConnectionProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.currentTenantIdentifierResolver != null) {
|
|
||||||
sfb.setCurrentTenantIdentifierResolver(this.currentTenantIdentifierResolver);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.cacheRegionFactory != null) {
|
|
||||||
sfb.setCacheRegionFactory(this.cacheRegionFactory);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.entityTypeFilters != null) {
|
|
||||||
sfb.setEntityTypeFilters(this.entityTypeFilters);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.hibernateProperties != null) {
|
|
||||||
sfb.addProperties(this.hibernateProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.annotatedClasses != null) {
|
|
||||||
sfb.addAnnotatedClasses(this.annotatedClasses);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.annotatedPackages != null) {
|
|
||||||
sfb.addPackages(this.annotatedPackages);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.packagesToScan != null) {
|
|
||||||
sfb.scanPackages(this.packagesToScan);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build SessionFactory instance.
|
|
||||||
this.configuration = sfb;
|
|
||||||
this.sessionFactory = buildSessionFactory(sfb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subclasses can override this method to perform custom initialization
|
|
||||||
* of the SessionFactory instance, creating it via the given Configuration
|
|
||||||
* object that got prepared by this LocalSessionFactoryBean.
|
|
||||||
* <p>The default implementation invokes LocalSessionFactoryBuilder's buildSessionFactory.
|
|
||||||
* A custom implementation could prepare the instance in a specific way (e.g. applying
|
|
||||||
* a custom ServiceRegistry) or use a custom SessionFactoryImpl subclass.
|
|
||||||
* @param sfb LocalSessionFactoryBuilder prepared by this LocalSessionFactoryBean
|
|
||||||
* @return the SessionFactory instance
|
|
||||||
* @see LocalSessionFactoryBuilder#buildSessionFactory
|
|
||||||
*/
|
|
||||||
protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
|
|
||||||
return sfb.buildSessionFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the Hibernate Configuration object used to build the SessionFactory.
|
|
||||||
* Allows for access to configuration metadata stored there (rarely needed).
|
|
||||||
* @throws IllegalStateException if the Configuration object has not been initialized yet
|
|
||||||
*/
|
|
||||||
public final Configuration getConfiguration() {
|
|
||||||
if (this.configuration == null) {
|
|
||||||
throw new IllegalStateException("Configuration not initialized yet");
|
|
||||||
}
|
|
||||||
return this.configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SessionFactory getObject() {
|
|
||||||
return this.sessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?> getObjectType() {
|
|
||||||
return (this.sessionFactory != null ? this.sessionFactory.getClass() : SessionFactory.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSingleton() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void destroy() {
|
|
||||||
this.sessionFactory.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,393 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
import javax.persistence.AttributeConverter;
|
|
||||||
import javax.persistence.Embeddable;
|
|
||||||
import javax.persistence.Entity;
|
|
||||||
import javax.persistence.MappedSuperclass;
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
import javax.transaction.TransactionManager;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.MappingException;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
import org.hibernate.cache.spi.RegionFactory;
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.cfg.Configuration;
|
|
||||||
import org.hibernate.cfg.Environment;
|
|
||||||
import org.hibernate.cfg.Settings;
|
|
||||||
import org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory;
|
|
||||||
import org.hibernate.service.ServiceRegistry;
|
|
||||||
|
|
||||||
import org.springframework.core.io.Resource;
|
|
||||||
import org.springframework.core.io.ResourceLoader;
|
|
||||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
|
||||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
|
||||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
|
||||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
|
||||||
import org.springframework.core.type.classreading.MetadataReader;
|
|
||||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
|
||||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
|
||||||
import org.springframework.core.type.filter.TypeFilter;
|
|
||||||
import org.springframework.transaction.jta.JtaTransactionManager;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Spring-provided extension of the standard Hibernate {@link Configuration} class,
|
|
||||||
* adding {@link SpringSessionContext} as a default and providing convenient ways
|
|
||||||
* to specify a DataSource and an application class loader.
|
|
||||||
*
|
|
||||||
* <p>This is designed for programmatic use, e.g. in {@code @Bean} factory methods.
|
|
||||||
* Consider using {@link LocalSessionFactoryBean} for XML bean definition files.
|
|
||||||
*
|
|
||||||
* <p><b>Requires Hibernate 4.0 or higher.</b> As of Spring 4.0, it is compatible with
|
|
||||||
* (the quite refactored) Hibernate 4.3 as well. We recommend using the latest
|
|
||||||
* Hibernate 4.2.x or 4.3.x version, depending on whether you need to remain JPA 2.0
|
|
||||||
* compatible at runtime (Hibernate 4.2) or can upgrade to JPA 2.1 (Hibernate 4.3).
|
|
||||||
*
|
|
||||||
* <p><b>NOTE:</b> To set up Hibernate 4 for Spring-driven JTA transactions, make
|
|
||||||
* sure to either use the {@link #setJtaTransactionManager} method or to set the
|
|
||||||
* "hibernate.transaction.factory_class" property to {@link CMTTransactionFactory}.
|
|
||||||
* Otherwise, Hibernate's smart flushing mechanism won't work properly.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
* @see LocalSessionFactoryBean
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class LocalSessionFactoryBuilder extends Configuration {
|
|
||||||
|
|
||||||
private static final String RESOURCE_PATTERN = "/**/*.class";
|
|
||||||
|
|
||||||
private static final String PACKAGE_INFO_SUFFIX = ".package-info";
|
|
||||||
|
|
||||||
private static final TypeFilter[] DEFAULT_ENTITY_TYPE_FILTERS = new TypeFilter[] {
|
|
||||||
new AnnotationTypeFilter(Entity.class, false),
|
|
||||||
new AnnotationTypeFilter(Embeddable.class, false),
|
|
||||||
new AnnotationTypeFilter(MappedSuperclass.class, false)};
|
|
||||||
|
|
||||||
|
|
||||||
private static TypeFilter converterTypeFilter;
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Class<? extends Annotation> converterAnnotation = (Class<? extends Annotation>)
|
|
||||||
ClassUtils.forName("javax.persistence.Converter", LocalSessionFactoryBuilder.class.getClassLoader());
|
|
||||||
converterTypeFilter = new AnnotationTypeFilter(converterAnnotation, false);
|
|
||||||
}
|
|
||||||
catch (ClassNotFoundException ex) {
|
|
||||||
// JPA 2.1 API not available - Hibernate <4.3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private final ResourcePatternResolver resourcePatternResolver;
|
|
||||||
|
|
||||||
private RegionFactory cacheRegionFactory;
|
|
||||||
|
|
||||||
private TypeFilter[] entityTypeFilters = DEFAULT_ENTITY_TYPE_FILTERS;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new LocalSessionFactoryBuilder for the given DataSource.
|
|
||||||
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
|
|
||||||
* (may be {@code null})
|
|
||||||
*/
|
|
||||||
public LocalSessionFactoryBuilder(DataSource dataSource) {
|
|
||||||
this(dataSource, new PathMatchingResourcePatternResolver());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new LocalSessionFactoryBuilder for the given DataSource.
|
|
||||||
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
|
|
||||||
* (may be {@code null})
|
|
||||||
* @param classLoader the ClassLoader to load application classes from
|
|
||||||
*/
|
|
||||||
public LocalSessionFactoryBuilder(DataSource dataSource, ClassLoader classLoader) {
|
|
||||||
this(dataSource, new PathMatchingResourcePatternResolver(classLoader));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new LocalSessionFactoryBuilder for the given DataSource.
|
|
||||||
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
|
|
||||||
* (may be {@code null})
|
|
||||||
* @param resourceLoader the ResourceLoader to load application classes from
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("deprecation") // to be able to build against Hibernate 4.3
|
|
||||||
public LocalSessionFactoryBuilder(DataSource dataSource, ResourceLoader resourceLoader) {
|
|
||||||
getProperties().put(Environment.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext.class.getName());
|
|
||||||
if (dataSource != null) {
|
|
||||||
getProperties().put(Environment.DATASOURCE, dataSource);
|
|
||||||
}
|
|
||||||
// APP_CLASSLOADER is deprecated as of Hibernate 4.3 but we need to remain compatible with 4.0+
|
|
||||||
getProperties().put(AvailableSettings.APP_CLASSLOADER, resourceLoader.getClassLoader());
|
|
||||||
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Spring {@link JtaTransactionManager} or the JTA {@link TransactionManager}
|
|
||||||
* to be used with Hibernate, if any. Allows for using a Spring-managed transaction
|
|
||||||
* manager for Hibernate 4's session and cache synchronization, with the
|
|
||||||
* "hibernate.transaction.jta.platform" automatically set to it. Also sets
|
|
||||||
* "hibernate.transaction.factory_class" to {@link CMTTransactionFactory},
|
|
||||||
* instructing Hibernate to interact with externally managed transactions.
|
|
||||||
* <p>A passed-in Spring {@link JtaTransactionManager} needs to contain a JTA
|
|
||||||
* {@link TransactionManager} reference to be usable here, except for the WebSphere
|
|
||||||
* case where we'll automatically set {@code WebSphereExtendedJtaPlatform} accordingly.
|
|
||||||
* <p>Note: If this is set, the Hibernate settings should not contain a JTA platform
|
|
||||||
* setting to avoid meaningless double configuration.
|
|
||||||
*/
|
|
||||||
public LocalSessionFactoryBuilder setJtaTransactionManager(Object jtaTransactionManager) {
|
|
||||||
Assert.notNull(jtaTransactionManager, "Transaction manager reference must not be null");
|
|
||||||
if (jtaTransactionManager instanceof JtaTransactionManager) {
|
|
||||||
boolean webspherePresent = ClassUtils.isPresent("com.ibm.wsspi.uow.UOWManager", getClass().getClassLoader());
|
|
||||||
if (webspherePresent) {
|
|
||||||
getProperties().put(AvailableSettings.JTA_PLATFORM,
|
|
||||||
ConfigurableJtaPlatform.getJtaPlatformBasePackage() + "internal.WebSphereExtendedJtaPlatform");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
JtaTransactionManager jtaTm = (JtaTransactionManager) jtaTransactionManager;
|
|
||||||
if (jtaTm.getTransactionManager() == null) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Can only apply JtaTransactionManager which has a TransactionManager reference set");
|
|
||||||
}
|
|
||||||
getProperties().put(AvailableSettings.JTA_PLATFORM,
|
|
||||||
new ConfigurableJtaPlatform(jtaTm.getTransactionManager(), jtaTm.getUserTransaction(),
|
|
||||||
jtaTm.getTransactionSynchronizationRegistry()).getJtaPlatformProxy());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (jtaTransactionManager instanceof TransactionManager) {
|
|
||||||
getProperties().put(AvailableSettings.JTA_PLATFORM,
|
|
||||||
new ConfigurableJtaPlatform((TransactionManager) jtaTransactionManager, null, null).getJtaPlatformProxy());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Unknown transaction manager type: " + jtaTransactionManager.getClass().getName());
|
|
||||||
}
|
|
||||||
getProperties().put(AvailableSettings.TRANSACTION_STRATEGY, new CMTTransactionFactory());
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a Hibernate 4.1/4.2/4.3 {@code MultiTenantConnectionProvider} to be passed
|
|
||||||
* on to the SessionFactory: as an instance, a Class, or a String class name.
|
|
||||||
* <p>Note that the package location of the {@code MultiTenantConnectionProvider}
|
|
||||||
* interface changed between Hibernate 4.2 and 4.3. This method accepts both variants.
|
|
||||||
* @since 4.0
|
|
||||||
* @see AvailableSettings#MULTI_TENANT_CONNECTION_PROVIDER
|
|
||||||
*/
|
|
||||||
public LocalSessionFactoryBuilder setMultiTenantConnectionProvider(Object multiTenantConnectionProvider) {
|
|
||||||
getProperties().put(AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProvider);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a Hibernate 4.1/4.2/4.3 {@code CurrentTenantIdentifierResolver} to be passed
|
|
||||||
* on to the SessionFactory: as an instance, a Class, or a String class name.
|
|
||||||
* @since 4.0
|
|
||||||
* @see AvailableSettings#MULTI_TENANT_IDENTIFIER_RESOLVER
|
|
||||||
*/
|
|
||||||
public LocalSessionFactoryBuilder setCurrentTenantIdentifierResolver(Object currentTenantIdentifierResolver) {
|
|
||||||
getProperties().put(AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolver);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Hibernate RegionFactory to use for the SessionFactory.
|
|
||||||
* Allows for using a Spring-managed RegionFactory instance.
|
|
||||||
* <p>Note: If this is set, the Hibernate settings should not define a
|
|
||||||
* cache provider to avoid meaningless double configuration.
|
|
||||||
* @since 4.0
|
|
||||||
* @see org.hibernate.cache.spi.RegionFactory
|
|
||||||
*/
|
|
||||||
public LocalSessionFactoryBuilder setCacheRegionFactory(RegionFactory cacheRegionFactory) {
|
|
||||||
this.cacheRegionFactory = cacheRegionFactory;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify custom type filters for Spring-based scanning for entity classes.
|
|
||||||
* <p>Default is to search all specified packages for classes annotated with
|
|
||||||
* {@code @javax.persistence.Entity}, {@code @javax.persistence.Embeddable}
|
|
||||||
* or {@code @javax.persistence.MappedSuperclass}.
|
|
||||||
* @since 4.1
|
|
||||||
* @see #scanPackages
|
|
||||||
*/
|
|
||||||
public LocalSessionFactoryBuilder setEntityTypeFilters(TypeFilter... entityTypeFilters) {
|
|
||||||
this.entityTypeFilters = entityTypeFilters;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the given annotated classes in a batch.
|
|
||||||
* @see #addAnnotatedClass
|
|
||||||
* @see #scanPackages
|
|
||||||
*/
|
|
||||||
public LocalSessionFactoryBuilder addAnnotatedClasses(Class<?>... annotatedClasses) {
|
|
||||||
for (Class<?> annotatedClass : annotatedClasses) {
|
|
||||||
addAnnotatedClass(annotatedClass);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the given annotated packages in a batch.
|
|
||||||
* @see #addPackage
|
|
||||||
* @see #scanPackages
|
|
||||||
*/
|
|
||||||
public LocalSessionFactoryBuilder addPackages(String... annotatedPackages) {
|
|
||||||
for (String annotatedPackage : annotatedPackages) {
|
|
||||||
addPackage(annotatedPackage);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform Spring-based scanning for entity classes, registering them
|
|
||||||
* as annotated classes with this {@code Configuration}.
|
|
||||||
* @param packagesToScan one or more Java package names
|
|
||||||
* @throws HibernateException if scanning fails for any reason
|
|
||||||
*/
|
|
||||||
public LocalSessionFactoryBuilder scanPackages(String... packagesToScan) throws HibernateException {
|
|
||||||
Set<String> entityClassNames = new TreeSet<String>();
|
|
||||||
Set<String> converterClassNames = new TreeSet<String>();
|
|
||||||
Set<String> packageNames = new TreeSet<String>();
|
|
||||||
try {
|
|
||||||
for (String pkg : packagesToScan) {
|
|
||||||
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
|
|
||||||
ClassUtils.convertClassNameToResourcePath(pkg) + RESOURCE_PATTERN;
|
|
||||||
Resource[] resources = this.resourcePatternResolver.getResources(pattern);
|
|
||||||
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
|
|
||||||
for (Resource resource : resources) {
|
|
||||||
if (resource.isReadable()) {
|
|
||||||
MetadataReader reader = readerFactory.getMetadataReader(resource);
|
|
||||||
String className = reader.getClassMetadata().getClassName();
|
|
||||||
if (matchesEntityTypeFilter(reader, readerFactory)) {
|
|
||||||
entityClassNames.add(className);
|
|
||||||
}
|
|
||||||
else if (converterTypeFilter != null && converterTypeFilter.match(reader, readerFactory)) {
|
|
||||||
converterClassNames.add(className);
|
|
||||||
}
|
|
||||||
else if (className.endsWith(PACKAGE_INFO_SUFFIX)) {
|
|
||||||
packageNames.add(className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException ex) {
|
|
||||||
throw new MappingException("Failed to scan classpath for unlisted classes", ex);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
ClassLoader cl = this.resourcePatternResolver.getClassLoader();
|
|
||||||
for (String className : entityClassNames) {
|
|
||||||
addAnnotatedClass(cl.loadClass(className));
|
|
||||||
}
|
|
||||||
for (String className : converterClassNames) {
|
|
||||||
ConverterRegistrationDelegate.registerConverter(this, cl.loadClass(className));
|
|
||||||
}
|
|
||||||
for (String packageName : packageNames) {
|
|
||||||
addPackage(packageName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ClassNotFoundException ex) {
|
|
||||||
throw new MappingException("Failed to load annotated classes from classpath", ex);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether any of the configured entity type filters matches
|
|
||||||
* the current class descriptor contained in the metadata reader.
|
|
||||||
*/
|
|
||||||
private boolean matchesEntityTypeFilter(MetadataReader reader, MetadataReaderFactory readerFactory) throws IOException {
|
|
||||||
if (this.entityTypeFilters != null) {
|
|
||||||
for (TypeFilter filter : this.entityTypeFilters) {
|
|
||||||
if (filter.match(reader, readerFactory)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Overridden methods from Hibernate's Configuration class
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Settings buildSettings(Properties props, ServiceRegistry serviceRegistry) throws HibernateException {
|
|
||||||
Settings settings = super.buildSettings(props, serviceRegistry);
|
|
||||||
if (this.cacheRegionFactory != null) {
|
|
||||||
try {
|
|
||||||
Method setRegionFactory = Settings.class.getDeclaredMethod("setRegionFactory", RegionFactory.class);
|
|
||||||
setRegionFactory.setAccessible(true);
|
|
||||||
setRegionFactory.invoke(settings, this.cacheRegionFactory);
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new IllegalStateException("Failed to invoke Hibernate's setRegionFactory method", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build the {@code SessionFactory}.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public SessionFactory buildSessionFactory() throws HibernateException {
|
|
||||||
ClassLoader appClassLoader = (ClassLoader) getProperties().get(AvailableSettings.APP_CLASSLOADER);
|
|
||||||
Thread currentThread = Thread.currentThread();
|
|
||||||
ClassLoader threadContextClassLoader = currentThread.getContextClassLoader();
|
|
||||||
boolean overrideClassLoader =
|
|
||||||
(appClassLoader != null && !appClassLoader.equals(threadContextClassLoader));
|
|
||||||
if (overrideClassLoader) {
|
|
||||||
currentThread.setContextClassLoader(appClassLoader);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return super.buildSessionFactory();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if (overrideClassLoader) {
|
|
||||||
currentThread.setContextClassLoader(threadContextClassLoader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inner class to avoid hard dependency on JPA 2.1 / Hibernate 4.3.
|
|
||||||
*/
|
|
||||||
private static class ConverterRegistrationDelegate {
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static void registerConverter(Configuration config, Class<?> converterClass) {
|
|
||||||
config.addAttributeConverter((Class<? extends AttributeConverter<?, ?>>) converterClass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,221 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.JDBCException;
|
|
||||||
import org.hibernate.NonUniqueObjectException;
|
|
||||||
import org.hibernate.NonUniqueResultException;
|
|
||||||
import org.hibernate.ObjectDeletedException;
|
|
||||||
import org.hibernate.PersistentObjectException;
|
|
||||||
import org.hibernate.PessimisticLockException;
|
|
||||||
import org.hibernate.PropertyValueException;
|
|
||||||
import org.hibernate.QueryException;
|
|
||||||
import org.hibernate.QueryTimeoutException;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
import org.hibernate.StaleObjectStateException;
|
|
||||||
import org.hibernate.StaleStateException;
|
|
||||||
import org.hibernate.TransientObjectException;
|
|
||||||
import org.hibernate.UnresolvableObjectException;
|
|
||||||
import org.hibernate.WrongClassException;
|
|
||||||
import org.hibernate.dialect.lock.OptimisticEntityLockException;
|
|
||||||
import org.hibernate.dialect.lock.PessimisticEntityLockException;
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|
||||||
import org.hibernate.exception.ConstraintViolationException;
|
|
||||||
import org.hibernate.exception.DataException;
|
|
||||||
import org.hibernate.exception.JDBCConnectionException;
|
|
||||||
import org.hibernate.exception.LockAcquisitionException;
|
|
||||||
import org.hibernate.exception.SQLGrammarException;
|
|
||||||
import org.hibernate.service.spi.Wrapped;
|
|
||||||
|
|
||||||
import org.springframework.dao.CannotAcquireLockException;
|
|
||||||
import org.springframework.dao.DataAccessException;
|
|
||||||
import org.springframework.dao.DataAccessResourceFailureException;
|
|
||||||
import org.springframework.dao.DataIntegrityViolationException;
|
|
||||||
import org.springframework.dao.DuplicateKeyException;
|
|
||||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
|
||||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
|
||||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
|
||||||
import org.springframework.dao.PessimisticLockingFailureException;
|
|
||||||
import org.springframework.jdbc.datasource.DataSourceUtils;
|
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
import org.springframework.util.ReflectionUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class featuring methods for Hibernate Session handling.
|
|
||||||
* Also provides support for exception translation.
|
|
||||||
*
|
|
||||||
* <p>Used internally by {@link HibernateTransactionManager}.
|
|
||||||
* Can also be used directly in application code.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
* @see HibernateExceptionTranslator
|
|
||||||
* @see HibernateTransactionManager
|
|
||||||
*/
|
|
||||||
public abstract class SessionFactoryUtils {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Order value for TransactionSynchronization objects that clean up Hibernate Sessions.
|
|
||||||
* Returns {@code DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100}
|
|
||||||
* to execute Session cleanup before JDBC Connection cleanup, if any.
|
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#CONNECTION_SYNCHRONIZATION_ORDER
|
|
||||||
*/
|
|
||||||
public static final int SESSION_SYNCHRONIZATION_ORDER =
|
|
||||||
DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100;
|
|
||||||
|
|
||||||
static final Log logger = LogFactory.getLog(SessionFactoryUtils.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bridging between the different ConnectionProvider package location in 4.0-4.2 vs 4.3.
|
|
||||||
*/
|
|
||||||
private static final Method getConnectionProviderMethod =
|
|
||||||
ClassUtils.getMethodIfAvailable(SessionFactoryImplementor.class, "getConnectionProvider");
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine the DataSource of the given SessionFactory.
|
|
||||||
* @param sessionFactory the SessionFactory to check
|
|
||||||
* @return the DataSource, or {@code null} if none found
|
|
||||||
* @see org.hibernate.engine.spi.SessionFactoryImplementor#getConnectionProvider
|
|
||||||
*/
|
|
||||||
public static DataSource getDataSource(SessionFactory sessionFactory) {
|
|
||||||
if (getConnectionProviderMethod != null && sessionFactory instanceof SessionFactoryImplementor) {
|
|
||||||
Wrapped cp = (Wrapped) ReflectionUtils.invokeMethod(getConnectionProviderMethod, sessionFactory);
|
|
||||||
if (cp != null) {
|
|
||||||
return cp.unwrap(DataSource.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform actual closing of the Hibernate Session,
|
|
||||||
* catching and logging any cleanup exceptions thrown.
|
|
||||||
* @param session the Hibernate Session to close (may be {@code null})
|
|
||||||
* @see org.hibernate.Session#close()
|
|
||||||
*/
|
|
||||||
public static void closeSession(Session session) {
|
|
||||||
if (session != null) {
|
|
||||||
try {
|
|
||||||
session.close();
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
logger.debug("Could not close Hibernate Session", ex);
|
|
||||||
}
|
|
||||||
catch (Throwable ex) {
|
|
||||||
logger.debug("Unexpected exception on closing Hibernate Session", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the given HibernateException to an appropriate exception
|
|
||||||
* from the {@code org.springframework.dao} hierarchy.
|
|
||||||
* @param ex HibernateException that occurred
|
|
||||||
* @return the corresponding DataAccessException instance
|
|
||||||
* @see HibernateExceptionTranslator#convertHibernateAccessException
|
|
||||||
* @see HibernateTransactionManager#convertHibernateAccessException
|
|
||||||
*/
|
|
||||||
public static DataAccessException convertHibernateAccessException(HibernateException ex) {
|
|
||||||
if (ex instanceof JDBCConnectionException) {
|
|
||||||
return new DataAccessResourceFailureException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof SQLGrammarException) {
|
|
||||||
SQLGrammarException jdbcEx = (SQLGrammarException) ex;
|
|
||||||
return new InvalidDataAccessResourceUsageException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof QueryTimeoutException) {
|
|
||||||
QueryTimeoutException jdbcEx = (QueryTimeoutException) ex;
|
|
||||||
return new org.springframework.dao.QueryTimeoutException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof LockAcquisitionException) {
|
|
||||||
LockAcquisitionException jdbcEx = (LockAcquisitionException) ex;
|
|
||||||
return new CannotAcquireLockException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof PessimisticLockException) {
|
|
||||||
PessimisticLockException jdbcEx = (PessimisticLockException) ex;
|
|
||||||
return new PessimisticLockingFailureException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof ConstraintViolationException) {
|
|
||||||
ConstraintViolationException jdbcEx = (ConstraintViolationException) ex;
|
|
||||||
return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() +
|
|
||||||
"]; constraint [" + jdbcEx.getConstraintName() + "]", ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof DataException) {
|
|
||||||
DataException jdbcEx = (DataException) ex;
|
|
||||||
return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof JDBCException) {
|
|
||||||
return new HibernateJdbcException((JDBCException) ex);
|
|
||||||
}
|
|
||||||
// end of JDBCException (subclass) handling
|
|
||||||
|
|
||||||
if (ex instanceof QueryException) {
|
|
||||||
return new HibernateQueryException((QueryException) ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof NonUniqueResultException) {
|
|
||||||
return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof NonUniqueObjectException) {
|
|
||||||
return new DuplicateKeyException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof PropertyValueException) {
|
|
||||||
return new DataIntegrityViolationException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof PersistentObjectException) {
|
|
||||||
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof TransientObjectException) {
|
|
||||||
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof ObjectDeletedException) {
|
|
||||||
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof UnresolvableObjectException) {
|
|
||||||
return new HibernateObjectRetrievalFailureException((UnresolvableObjectException) ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof WrongClassException) {
|
|
||||||
return new HibernateObjectRetrievalFailureException((WrongClassException) ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof StaleObjectStateException) {
|
|
||||||
return new HibernateOptimisticLockingFailureException((StaleObjectStateException) ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof StaleStateException) {
|
|
||||||
return new HibernateOptimisticLockingFailureException((StaleStateException) ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof OptimisticEntityLockException) {
|
|
||||||
return new HibernateOptimisticLockingFailureException((OptimisticEntityLockException) ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof PessimisticEntityLockException) {
|
|
||||||
if (ex.getCause() instanceof LockAcquisitionException) {
|
|
||||||
return new CannotAcquireLockException(ex.getMessage(), ex.getCause());
|
|
||||||
}
|
|
||||||
return new PessimisticLockingFailureException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// fallback
|
|
||||||
return new HibernateSystemException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
||||||
import org.hibernate.FlushMode;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.Transaction;
|
|
||||||
|
|
||||||
import org.springframework.transaction.support.ResourceHolderSupport;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Session holder, wrapping a Hibernate Session and a Hibernate Transaction.
|
|
||||||
* HibernateTransactionManager binds instances of this class to the thread,
|
|
||||||
* for a given SessionFactory.
|
|
||||||
*
|
|
||||||
* <p>Note: This is an SPI class, not intended to be used by applications.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
* @see HibernateTransactionManager
|
|
||||||
* @see SessionFactoryUtils
|
|
||||||
*/
|
|
||||||
public class SessionHolder extends ResourceHolderSupport {
|
|
||||||
|
|
||||||
private Session session;
|
|
||||||
|
|
||||||
private Transaction transaction;
|
|
||||||
|
|
||||||
private FlushMode previousFlushMode;
|
|
||||||
|
|
||||||
|
|
||||||
public SessionHolder(Session session) {
|
|
||||||
Assert.notNull(session, "Session must not be null");
|
|
||||||
this.session = session;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Session getSession() {
|
|
||||||
return this.session;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTransaction(Transaction transaction) {
|
|
||||||
this.transaction = transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Transaction getTransaction() {
|
|
||||||
return this.transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPreviousFlushMode(FlushMode previousFlushMode) {
|
|
||||||
this.previousFlushMode = previousFlushMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FlushMode getPreviousFlushMode() {
|
|
||||||
return this.previousFlushMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
super.clear();
|
|
||||||
this.transaction = null;
|
|
||||||
this.previousFlushMode = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple synchronization adapter that propagates a {@code flush()} call
|
|
||||||
* to the underlying Hibernate Session. Used in combination with JTA.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
*/
|
|
||||||
public class SpringFlushSynchronization extends TransactionSynchronizationAdapter {
|
|
||||||
|
|
||||||
private final Session session;
|
|
||||||
|
|
||||||
|
|
||||||
public SpringFlushSynchronization(Session session) {
|
|
||||||
this.session = session;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void flush() {
|
|
||||||
try {
|
|
||||||
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on explicit request");
|
|
||||||
this.session.flush();
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
throw SessionFactoryUtils.convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
return (obj instanceof SpringFlushSynchronization &&
|
|
||||||
this.session == ((SpringFlushSynchronization) obj).session);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return this.session.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
||||||
import org.hibernate.FlushMode;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.context.internal.JTASessionContext;
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|
||||||
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spring-specific subclass of Hibernate's JTASessionContext,
|
|
||||||
* setting {@code FlushMode.MANUAL} for read-only transactions.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class SpringJtaSessionContext extends JTASessionContext {
|
|
||||||
|
|
||||||
public SpringJtaSessionContext(SessionFactoryImplementor factory) {
|
|
||||||
super(factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Session buildOrObtainSession() {
|
|
||||||
Session session = super.buildOrObtainSession();
|
|
||||||
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
|
||||||
}
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,138 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import javax.transaction.Status;
|
|
||||||
import javax.transaction.SystemException;
|
|
||||||
import javax.transaction.TransactionManager;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.hibernate.FlushMode;
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.context.spi.CurrentSessionContext;
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|
||||||
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
||||||
import org.springframework.util.ReflectionUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of Hibernate 3.1's CurrentSessionContext interface
|
|
||||||
* that delegates to Spring's SessionFactoryUtils for providing a
|
|
||||||
* Spring-managed current Session.
|
|
||||||
*
|
|
||||||
* <p>This CurrentSessionContext implementation can also be specified in custom
|
|
||||||
* SessionFactory setup through the "hibernate.current_session_context_class"
|
|
||||||
* property, with the fully qualified name of this class as value.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class SpringSessionContext implements CurrentSessionContext {
|
|
||||||
|
|
||||||
private final SessionFactoryImplementor sessionFactory;
|
|
||||||
|
|
||||||
private TransactionManager transactionManager;
|
|
||||||
|
|
||||||
private CurrentSessionContext jtaSessionContext;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new SpringSessionContext for the given Hibernate SessionFactory.
|
|
||||||
* @param sessionFactory the SessionFactory to provide current Sessions for
|
|
||||||
*/
|
|
||||||
public SpringSessionContext(SessionFactoryImplementor sessionFactory) {
|
|
||||||
this.sessionFactory = sessionFactory;
|
|
||||||
try {
|
|
||||||
Object jtaPlatform = sessionFactory.getServiceRegistry().getService(ConfigurableJtaPlatform.jtaPlatformClass);
|
|
||||||
Method rtmMethod = ConfigurableJtaPlatform.jtaPlatformClass.getMethod("retrieveTransactionManager");
|
|
||||||
this.transactionManager = (TransactionManager) ReflectionUtils.invokeMethod(rtmMethod, jtaPlatform);
|
|
||||||
if (this.transactionManager != null) {
|
|
||||||
this.jtaSessionContext = new SpringJtaSessionContext(sessionFactory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
LogFactory.getLog(SpringSessionContext.class).warn(
|
|
||||||
"Could not introspect Hibernate JtaPlatform for SpringJtaSessionContext", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the Spring-managed Session for the current thread, if any.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Session currentSession() throws HibernateException {
|
|
||||||
Object value = TransactionSynchronizationManager.getResource(this.sessionFactory);
|
|
||||||
if (value instanceof Session) {
|
|
||||||
return (Session) value;
|
|
||||||
}
|
|
||||||
else if (value instanceof SessionHolder) {
|
|
||||||
SessionHolder sessionHolder = (SessionHolder) value;
|
|
||||||
Session session = sessionHolder.getSession();
|
|
||||||
if (!sessionHolder.isSynchronizedWithTransaction() &&
|
|
||||||
TransactionSynchronizationManager.isSynchronizationActive()) {
|
|
||||||
TransactionSynchronizationManager.registerSynchronization(
|
|
||||||
new SpringSessionSynchronization(sessionHolder, this.sessionFactory, false));
|
|
||||||
sessionHolder.setSynchronizedWithTransaction(true);
|
|
||||||
// Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
|
|
||||||
// with FlushMode.MANUAL, which needs to allow flushing within the transaction.
|
|
||||||
FlushMode flushMode = session.getFlushMode();
|
|
||||||
if (flushMode.equals(FlushMode.MANUAL) &&
|
|
||||||
!TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
|
|
||||||
session.setFlushMode(FlushMode.AUTO);
|
|
||||||
sessionHolder.setPreviousFlushMode(flushMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.transactionManager != null) {
|
|
||||||
try {
|
|
||||||
if (this.transactionManager.getStatus() == Status.STATUS_ACTIVE) {
|
|
||||||
Session session = this.jtaSessionContext.currentSession();
|
|
||||||
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
|
||||||
TransactionSynchronizationManager.registerSynchronization(new SpringFlushSynchronization(session));
|
|
||||||
}
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (SystemException ex) {
|
|
||||||
throw new HibernateException("JTA TransactionManager found but status check failed", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
|
||||||
Session session = this.sessionFactory.openSession();
|
|
||||||
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
|
||||||
}
|
|
||||||
SessionHolder sessionHolder = new SessionHolder(session);
|
|
||||||
TransactionSynchronizationManager.registerSynchronization(
|
|
||||||
new SpringSessionSynchronization(sessionHolder, this.sessionFactory, true));
|
|
||||||
TransactionSynchronizationManager.bindResource(this.sessionFactory, sessionHolder);
|
|
||||||
sessionHolder.setSynchronizedWithTransaction(true);
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new HibernateException("Could not obtain transaction-synchronized Session for current thread");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,155 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2015 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
||||||
import org.hibernate.FlushMode;
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
|
|
||||||
import org.springframework.core.Ordered;
|
|
||||||
import org.springframework.dao.DataAccessException;
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronization;
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for resource cleanup at the end of a Spring-managed transaction
|
|
||||||
* for a pre-bound Hibernate Session.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
*/
|
|
||||||
public class SpringSessionSynchronization implements TransactionSynchronization, Ordered {
|
|
||||||
|
|
||||||
private final SessionHolder sessionHolder;
|
|
||||||
|
|
||||||
private final SessionFactory sessionFactory;
|
|
||||||
|
|
||||||
private final boolean newSession;
|
|
||||||
|
|
||||||
private boolean holderActive = true;
|
|
||||||
|
|
||||||
|
|
||||||
public SpringSessionSynchronization(SessionHolder sessionHolder, SessionFactory sessionFactory) {
|
|
||||||
this(sessionHolder, sessionFactory, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SpringSessionSynchronization(SessionHolder sessionHolder, SessionFactory sessionFactory, boolean newSession) {
|
|
||||||
this.sessionHolder = sessionHolder;
|
|
||||||
this.sessionFactory = sessionFactory;
|
|
||||||
this.newSession = newSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private Session getCurrentSession() {
|
|
||||||
return this.sessionHolder.getSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getOrder() {
|
|
||||||
return SessionFactoryUtils.SESSION_SYNCHRONIZATION_ORDER;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void suspend() {
|
|
||||||
if (this.holderActive) {
|
|
||||||
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
|
|
||||||
// Eagerly disconnect the Session here, to make release mode "on_close" work on JBoss.
|
|
||||||
getCurrentSession().disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void resume() {
|
|
||||||
if (this.holderActive) {
|
|
||||||
TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void flush() {
|
|
||||||
try {
|
|
||||||
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on explicit request");
|
|
||||||
getCurrentSession().flush();
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
throw SessionFactoryUtils.convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void beforeCommit(boolean readOnly) throws DataAccessException {
|
|
||||||
if (!readOnly) {
|
|
||||||
Session session = getCurrentSession();
|
|
||||||
// Read-write transaction -> flush the Hibernate Session.
|
|
||||||
// Further check: only flush when not FlushMode.MANUAL.
|
|
||||||
if (!session.getFlushMode().equals(FlushMode.MANUAL)) {
|
|
||||||
try {
|
|
||||||
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on transaction synchronization");
|
|
||||||
session.flush();
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
throw SessionFactoryUtils.convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void beforeCompletion() {
|
|
||||||
try {
|
|
||||||
Session session = this.sessionHolder.getSession();
|
|
||||||
if (this.sessionHolder.getPreviousFlushMode() != null) {
|
|
||||||
// In case of pre-bound Session, restore previous flush mode.
|
|
||||||
session.setFlushMode(this.sessionHolder.getPreviousFlushMode());
|
|
||||||
}
|
|
||||||
// Eagerly disconnect the Session here, to make release mode "on_close" work nicely.
|
|
||||||
session.disconnect();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
// Unbind at this point if it's a new Session...
|
|
||||||
if (this.newSession) {
|
|
||||||
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
|
|
||||||
this.holderActive = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterCommit() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterCompletion(int status) {
|
|
||||||
try {
|
|
||||||
if (status != STATUS_COMMITTED) {
|
|
||||||
// Clear all pending inserts/updates/deletes in the Session.
|
|
||||||
// Necessary for pre-bound Sessions, to avoid inconsistent state.
|
|
||||||
this.sessionHolder.getSession().clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
this.sessionHolder.setSynchronizedWithTransaction(false);
|
|
||||||
// Call close() at this point if it's a new Session...
|
|
||||||
if (this.newSession) {
|
|
||||||
SessionFactoryUtils.closeSession(this.sessionHolder.getSession());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
/**
|
|
||||||
* Package providing integration of
|
|
||||||
* <a href="http://www.hibernate.org">Hibernate 4.x</a>
|
|
||||||
* with Spring concepts.
|
|
||||||
*
|
|
||||||
* <p>Contains an implementation of Spring's transaction SPI for local Hibernate transactions.
|
|
||||||
* This package is intentionally rather minimal, with no template classes or the like,
|
|
||||||
* in order to follow Hibernate recommendations as closely as possible. We recommend
|
|
||||||
* using Hibernate's native <code>sessionFactory.getCurrentSession()</code> style.
|
|
||||||
*
|
|
||||||
* <p><b>This package supports Hibernate 4.x only.</b>
|
|
||||||
* See the {@code org.springframework.orm.hibernate3} package for Hibernate 3.x support.
|
|
||||||
* <b>Note:</b> Do not use HibernateTemplate or other classes from the hibernate3 package
|
|
||||||
* with Hibernate 4; this will lead to class definition exceptions at runtime.
|
|
||||||
*/
|
|
||||||
package org.springframework.orm.hibernate4;
|
|
||||||
|
|
@ -1,120 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2015 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4.support;
|
|
||||||
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
|
|
||||||
import org.springframework.orm.hibernate4.SessionFactoryUtils;
|
|
||||||
import org.springframework.orm.hibernate4.SessionHolder;
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
||||||
import org.springframework.web.context.request.NativeWebRequest;
|
|
||||||
import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
|
|
||||||
import org.springframework.web.context.request.async.DeferredResult;
|
|
||||||
import org.springframework.web.context.request.async.DeferredResultProcessingInterceptor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interceptor with asynchronous web requests used in OpenSessionInViewFilter and
|
|
||||||
* OpenSessionInViewInterceptor.
|
|
||||||
*
|
|
||||||
* Ensures the following:
|
|
||||||
* 1) The session is bound/unbound when "callable processing" is started
|
|
||||||
* 2) The session is closed if an async request times out
|
|
||||||
*
|
|
||||||
* @author Rossen Stoyanchev
|
|
||||||
* @since 3.2.5
|
|
||||||
*/
|
|
||||||
class AsyncRequestInterceptor extends CallableProcessingInterceptorAdapter implements DeferredResultProcessingInterceptor {
|
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(AsyncRequestInterceptor.class);
|
|
||||||
|
|
||||||
private final SessionFactory sessionFactory;
|
|
||||||
|
|
||||||
private final SessionHolder sessionHolder;
|
|
||||||
|
|
||||||
private volatile boolean timeoutInProgress;
|
|
||||||
|
|
||||||
|
|
||||||
public AsyncRequestInterceptor(SessionFactory sessionFactory, SessionHolder sessionHolder) {
|
|
||||||
this.sessionFactory = sessionFactory;
|
|
||||||
this.sessionHolder = sessionHolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void preProcess(NativeWebRequest request, Callable<T> task) {
|
|
||||||
bindSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void bindSession() {
|
|
||||||
this.timeoutInProgress = false;
|
|
||||||
TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
|
|
||||||
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) {
|
|
||||||
this.timeoutInProgress = true;
|
|
||||||
return RESULT_NONE; // give other interceptors a chance to handle the timeout
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void afterCompletion(NativeWebRequest request, Callable<T> task) throws Exception {
|
|
||||||
closeAfterTimeout();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void closeAfterTimeout() {
|
|
||||||
if (this.timeoutInProgress) {
|
|
||||||
logger.debug("Closing Hibernate Session after async request timeout");
|
|
||||||
SessionFactoryUtils.closeSession(this.sessionHolder.getSession());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Implementation of DeferredResultProcessingInterceptor methods
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void beforeConcurrentHandling(NativeWebRequest request, DeferredResult<T> deferredResult) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void preProcess(NativeWebRequest request, DeferredResult<T> deferredResult) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void postProcess(NativeWebRequest request, DeferredResult<T> deferredResult, Object result) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> boolean handleTimeout(NativeWebRequest request, DeferredResult<T> deferredResult) {
|
|
||||||
this.timeoutInProgress = true;
|
|
||||||
return true; // give other interceptors a chance to handle the timeout
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void afterCompletion(NativeWebRequest request, DeferredResult<T> deferredResult) {
|
|
||||||
closeAfterTimeout();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,132 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4.support;
|
|
||||||
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessResourceFailureException;
|
|
||||||
import org.springframework.dao.support.DaoSupport;
|
|
||||||
import org.springframework.orm.hibernate4.HibernateTemplate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenient super class for Hibernate-based data access objects.
|
|
||||||
*
|
|
||||||
* <p>Requires a {@link org.hibernate.SessionFactory} to be set, providing a
|
|
||||||
* {@link org.springframework.orm.hibernate4.HibernateTemplate} based on it to
|
|
||||||
* subclasses through the {@link #getHibernateTemplate()} method.
|
|
||||||
* Can alternatively be initialized directly with a HibernateTemplate,
|
|
||||||
* in order to reuse the latter's settings such as the SessionFactory,
|
|
||||||
* exception translator, flush mode, etc.
|
|
||||||
*
|
|
||||||
* <p>This class will create its own HibernateTemplate instance if a SessionFactory
|
|
||||||
* is passed in. The "allowCreate" flag on that HibernateTemplate will be "true"
|
|
||||||
* by default. A custom HibernateTemplate instance can be used through overriding
|
|
||||||
* {@link #createHibernateTemplate}.
|
|
||||||
*
|
|
||||||
* <p><b>NOTE: Hibernate access code can also be coded in plain Hibernate style.
|
|
||||||
* Hence, for newly started projects, consider adopting the standard Hibernate
|
|
||||||
* style of coding data access objects instead, based on
|
|
||||||
* {@link org.hibernate.SessionFactory#getCurrentSession()}.
|
|
||||||
* This HibernateTemplate primarily exists as a migration helper for Hibernate 3
|
|
||||||
* based data access code, to benefit from bug fixes in Hibernate 4.x.</b>
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 4.0.1
|
|
||||||
* @see #setSessionFactory
|
|
||||||
* @see #getHibernateTemplate
|
|
||||||
* @see org.springframework.orm.hibernate4.HibernateTemplate
|
|
||||||
*/
|
|
||||||
public abstract class HibernateDaoSupport extends DaoSupport {
|
|
||||||
|
|
||||||
private HibernateTemplate hibernateTemplate;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Hibernate SessionFactory to be used by this DAO.
|
|
||||||
* Will automatically create a HibernateTemplate for the given SessionFactory.
|
|
||||||
* @see #createHibernateTemplate
|
|
||||||
* @see #setHibernateTemplate
|
|
||||||
*/
|
|
||||||
public final void setSessionFactory(SessionFactory sessionFactory) {
|
|
||||||
if (this.hibernateTemplate == null || sessionFactory != this.hibernateTemplate.getSessionFactory()) {
|
|
||||||
this.hibernateTemplate = createHibernateTemplate(sessionFactory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a HibernateTemplate for the given SessionFactory.
|
|
||||||
* Only invoked if populating the DAO with a SessionFactory reference!
|
|
||||||
* <p>Can be overridden in subclasses to provide a HibernateTemplate instance
|
|
||||||
* with different configuration, or a custom HibernateTemplate subclass.
|
|
||||||
* @param sessionFactory the Hibernate SessionFactory to create a HibernateTemplate for
|
|
||||||
* @return the new HibernateTemplate instance
|
|
||||||
* @see #setSessionFactory
|
|
||||||
*/
|
|
||||||
protected HibernateTemplate createHibernateTemplate(SessionFactory sessionFactory) {
|
|
||||||
return new HibernateTemplate(sessionFactory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the Hibernate SessionFactory used by this DAO.
|
|
||||||
*/
|
|
||||||
public final SessionFactory getSessionFactory() {
|
|
||||||
return (this.hibernateTemplate != null ? this.hibernateTemplate.getSessionFactory() : null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the HibernateTemplate for this DAO explicitly,
|
|
||||||
* as an alternative to specifying a SessionFactory.
|
|
||||||
* @see #setSessionFactory
|
|
||||||
*/
|
|
||||||
public final void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
|
|
||||||
this.hibernateTemplate = hibernateTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the HibernateTemplate for this DAO,
|
|
||||||
* pre-initialized with the SessionFactory or set explicitly.
|
|
||||||
* <p><b>Note: The returned HibernateTemplate is a shared instance.</b>
|
|
||||||
* You may introspect its configuration, but not modify the configuration
|
|
||||||
* (other than from within an {@link #initDao} implementation).
|
|
||||||
* Consider creating a custom HibernateTemplate instance via
|
|
||||||
* {@code new HibernateTemplate(getSessionFactory())}, in which case
|
|
||||||
* you're allowed to customize the settings on the resulting instance.
|
|
||||||
*/
|
|
||||||
public final HibernateTemplate getHibernateTemplate() {
|
|
||||||
return this.hibernateTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected final void checkDaoConfig() {
|
|
||||||
if (this.hibernateTemplate == null) {
|
|
||||||
throw new IllegalArgumentException("'sessionFactory' or 'hibernateTemplate' is required");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Conveniently obtain the current Hibernate Session.
|
|
||||||
* @return the Hibernate Session
|
|
||||||
* @throws DataAccessResourceFailureException if the Session couldn't be created
|
|
||||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
|
||||||
*/
|
|
||||||
protected final Session currentSession() throws DataAccessResourceFailureException {
|
|
||||||
return getSessionFactory().getCurrentSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,221 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2015 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4.support;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import javax.servlet.FilterChain;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import org.hibernate.FlushMode;
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessResourceFailureException;
|
|
||||||
import org.springframework.orm.hibernate4.SessionFactoryUtils;
|
|
||||||
import org.springframework.orm.hibernate4.SessionHolder;
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
||||||
import org.springframework.web.context.WebApplicationContext;
|
|
||||||
import org.springframework.web.context.request.async.WebAsyncManager;
|
|
||||||
import org.springframework.web.context.request.async.WebAsyncUtils;
|
|
||||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Servlet Filter that binds a Hibernate Session to the thread for the entire
|
|
||||||
* processing of the request. Intended for the "Open Session in View" pattern,
|
|
||||||
* i.e. to allow for lazy loading in web views despite the original transactions
|
|
||||||
* already being completed.
|
|
||||||
*
|
|
||||||
* <p>This filter makes Hibernate Sessions available via the current thread, which
|
|
||||||
* will be autodetected by transaction managers. It is suitable for service layer
|
|
||||||
* transactions via {@link org.springframework.orm.hibernate4.HibernateTransactionManager}
|
|
||||||
* as well as for non-transactional execution (if configured appropriately).
|
|
||||||
*
|
|
||||||
* <p><b>NOTE</b>: This filter will by default <i>not</i> flush the Hibernate Session,
|
|
||||||
* with the flush mode set to {@code FlushMode.NEVER}. It assumes to be used
|
|
||||||
* in combination with service layer transactions that care for the flushing: The
|
|
||||||
* active transaction manager will temporarily change the flush mode to
|
|
||||||
* {@code FlushMode.AUTO} during a read-write transaction, with the flush
|
|
||||||
* mode reset to {@code FlushMode.NEVER} at the end of each transaction.
|
|
||||||
*
|
|
||||||
* <p><b>WARNING:</b> Applying this filter to existing logic can cause issues that
|
|
||||||
* have not appeared before, through the use of a single Hibernate Session for the
|
|
||||||
* processing of an entire request. In particular, the reassociation of persistent
|
|
||||||
* objects with a Hibernate Session has to occur at the very beginning of request
|
|
||||||
* processing, to avoid clashes with already loaded instances of the same objects.
|
|
||||||
*
|
|
||||||
* <p>Looks up the SessionFactory in Spring's root web application context.
|
|
||||||
* Supports a "sessionFactoryBeanName" filter init-param in {@code web.xml};
|
|
||||||
* the default bean name is "sessionFactory".
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
* @see #lookupSessionFactory
|
|
||||||
* @see OpenSessionInViewInterceptor
|
|
||||||
* @see OpenSessionInterceptor
|
|
||||||
* @see org.springframework.orm.hibernate4.HibernateTransactionManager
|
|
||||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
|
||||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
|
||||||
*/
|
|
||||||
public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
|
||||||
|
|
||||||
public static final String DEFAULT_SESSION_FACTORY_BEAN_NAME = "sessionFactory";
|
|
||||||
|
|
||||||
private String sessionFactoryBeanName = DEFAULT_SESSION_FACTORY_BEAN_NAME;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the bean name of the SessionFactory to fetch from Spring's
|
|
||||||
* root application context. Default is "sessionFactory".
|
|
||||||
* @see #DEFAULT_SESSION_FACTORY_BEAN_NAME
|
|
||||||
*/
|
|
||||||
public void setSessionFactoryBeanName(String sessionFactoryBeanName) {
|
|
||||||
this.sessionFactoryBeanName = sessionFactoryBeanName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the bean name of the SessionFactory to fetch from Spring's
|
|
||||||
* root application context.
|
|
||||||
*/
|
|
||||||
protected String getSessionFactoryBeanName() {
|
|
||||||
return this.sessionFactoryBeanName;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns "false" so that the filter may re-bind the opened Hibernate
|
|
||||||
* {@code Session} to each asynchronously dispatched thread and postpone
|
|
||||||
* closing it until the very last asynchronous dispatch.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected boolean shouldNotFilterAsyncDispatch() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns "false" so that the filter may provide a Hibernate
|
|
||||||
* {@code Session} to each error dispatches.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected boolean shouldNotFilterErrorDispatch() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doFilterInternal(
|
|
||||||
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
|
||||||
throws ServletException, IOException {
|
|
||||||
|
|
||||||
SessionFactory sessionFactory = lookupSessionFactory(request);
|
|
||||||
boolean participate = false;
|
|
||||||
|
|
||||||
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
|
|
||||||
String key = getAlreadyFilteredAttributeName();
|
|
||||||
|
|
||||||
if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
|
|
||||||
// Do not modify the Session: just set the participate flag.
|
|
||||||
participate = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
boolean isFirstRequest = !isAsyncDispatch(request);
|
|
||||||
if (isFirstRequest || !applySessionBindingInterceptor(asyncManager, key)) {
|
|
||||||
logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
|
|
||||||
Session session = openSession(sessionFactory);
|
|
||||||
SessionHolder sessionHolder = new SessionHolder(session);
|
|
||||||
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
|
|
||||||
|
|
||||||
AsyncRequestInterceptor interceptor = new AsyncRequestInterceptor(sessionFactory, sessionHolder);
|
|
||||||
asyncManager.registerCallableInterceptor(key, interceptor);
|
|
||||||
asyncManager.registerDeferredResultInterceptor(key, interceptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
filterChain.doFilter(request, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
finally {
|
|
||||||
if (!participate) {
|
|
||||||
SessionHolder sessionHolder =
|
|
||||||
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
|
|
||||||
if (!isAsyncStarted(request)) {
|
|
||||||
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
|
|
||||||
SessionFactoryUtils.closeSession(sessionHolder.getSession());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Look up the SessionFactory that this filter should use,
|
|
||||||
* taking the current HTTP request as argument.
|
|
||||||
* <p>The default implementation delegates to the {@link #lookupSessionFactory()}
|
|
||||||
* variant without arguments.
|
|
||||||
* @param request the current request
|
|
||||||
* @return the SessionFactory to use
|
|
||||||
*/
|
|
||||||
protected SessionFactory lookupSessionFactory(HttpServletRequest request) {
|
|
||||||
return lookupSessionFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Look up the SessionFactory that this filter should use.
|
|
||||||
* <p>The default implementation looks for a bean with the specified name
|
|
||||||
* in Spring's root application context.
|
|
||||||
* @return the SessionFactory to use
|
|
||||||
* @see #getSessionFactoryBeanName
|
|
||||||
*/
|
|
||||||
protected SessionFactory lookupSessionFactory() {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Using SessionFactory '" + getSessionFactoryBeanName() + "' for OpenSessionInViewFilter");
|
|
||||||
}
|
|
||||||
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
|
|
||||||
return wac.getBean(getSessionFactoryBeanName(), SessionFactory.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open a Session for the SessionFactory that this filter uses.
|
|
||||||
* <p>The default implementation delegates to the {@link SessionFactory#openSession}
|
|
||||||
* method and sets the {@link Session}'s flush mode to "MANUAL".
|
|
||||||
* @param sessionFactory the SessionFactory that this filter uses
|
|
||||||
* @return the Session to use
|
|
||||||
* @throws DataAccessResourceFailureException if the Session could not be created
|
|
||||||
* @see org.hibernate.FlushMode#MANUAL
|
|
||||||
*/
|
|
||||||
protected Session openSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
|
|
||||||
try {
|
|
||||||
Session session = sessionFactory.openSession();
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean applySessionBindingInterceptor(WebAsyncManager asyncManager, String key) {
|
|
||||||
if (asyncManager.getCallableInterceptor(key) == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,211 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4.support;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.hibernate.FlushMode;
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException;
|
|
||||||
import org.springframework.dao.DataAccessResourceFailureException;
|
|
||||||
import org.springframework.orm.hibernate4.SessionFactoryUtils;
|
|
||||||
import org.springframework.orm.hibernate4.SessionHolder;
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
||||||
import org.springframework.ui.ModelMap;
|
|
||||||
import org.springframework.web.context.request.AsyncWebRequestInterceptor;
|
|
||||||
import org.springframework.web.context.request.WebRequest;
|
|
||||||
import org.springframework.web.context.request.async.WebAsyncManager;
|
|
||||||
import org.springframework.web.context.request.async.WebAsyncUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spring web request interceptor that binds a Hibernate {@code Session} to the
|
|
||||||
* thread for the entire processing of the request.
|
|
||||||
*
|
|
||||||
* <p>This class is a concrete expression of the "Open Session in View" pattern, which
|
|
||||||
* is a pattern that allows for the lazy loading of associations in web views despite
|
|
||||||
* the original transactions already being completed.
|
|
||||||
*
|
|
||||||
* <p>This interceptor makes Hibernate Sessions available via the current thread,
|
|
||||||
* which will be autodetected by transaction managers. It is suitable for service layer
|
|
||||||
* transactions via {@link org.springframework.orm.hibernate4.HibernateTransactionManager}
|
|
||||||
* as well as for non-transactional execution (if configured appropriately).
|
|
||||||
*
|
|
||||||
* <p>In contrast to {@link OpenSessionInViewFilter}, this interceptor is configured
|
|
||||||
* in a Spring application context and can thus take advantage of bean wiring.
|
|
||||||
*
|
|
||||||
* <p><b>WARNING:</b> Applying this interceptor to existing logic can cause issues
|
|
||||||
* that have not appeared before, through the use of a single Hibernate
|
|
||||||
* {@code Session} for the processing of an entire request. In particular, the
|
|
||||||
* reassociation of persistent objects with a Hibernate {@code Session} has to
|
|
||||||
* occur at the very beginning of request processing, to avoid clashes with already
|
|
||||||
* loaded instances of the same objects.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
* @see OpenSessionInViewFilter
|
|
||||||
* @see OpenSessionInterceptor
|
|
||||||
* @see org.springframework.orm.hibernate4.HibernateTransactionManager
|
|
||||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
|
||||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
|
||||||
*/
|
|
||||||
public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Suffix that gets appended to the {@code SessionFactory}
|
|
||||||
* {@code toString()} representation for the "participate in existing
|
|
||||||
* session handling" request attribute.
|
|
||||||
* @see #getParticipateAttributeName
|
|
||||||
*/
|
|
||||||
public static final String PARTICIPATE_SUFFIX = ".PARTICIPATE";
|
|
||||||
|
|
||||||
protected final Log logger = LogFactory.getLog(getClass());
|
|
||||||
|
|
||||||
private SessionFactory sessionFactory;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Hibernate SessionFactory that should be used to create Hibernate Sessions.
|
|
||||||
*/
|
|
||||||
public void setSessionFactory(SessionFactory sessionFactory) {
|
|
||||||
this.sessionFactory = sessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the Hibernate SessionFactory that should be used to create Hibernate Sessions.
|
|
||||||
*/
|
|
||||||
public SessionFactory getSessionFactory() {
|
|
||||||
return this.sessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open a new Hibernate {@code Session} according and bind it to the thread via the
|
|
||||||
* {@link org.springframework.transaction.support.TransactionSynchronizationManager}.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void preHandle(WebRequest request) throws DataAccessException {
|
|
||||||
String participateAttributeName = getParticipateAttributeName();
|
|
||||||
|
|
||||||
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
|
|
||||||
if (asyncManager.hasConcurrentResult()) {
|
|
||||||
if (applySessionBindingInterceptor(asyncManager, participateAttributeName)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TransactionSynchronizationManager.hasResource(getSessionFactory())) {
|
|
||||||
// Do not modify the Session: just mark the request accordingly.
|
|
||||||
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
|
|
||||||
int newCount = (count != null ? count + 1 : 1);
|
|
||||||
request.setAttribute(getParticipateAttributeName(), newCount, WebRequest.SCOPE_REQUEST);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
logger.debug("Opening Hibernate Session in OpenSessionInViewInterceptor");
|
|
||||||
Session session = openSession();
|
|
||||||
SessionHolder sessionHolder = new SessionHolder(session);
|
|
||||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
|
|
||||||
|
|
||||||
AsyncRequestInterceptor asyncRequestInterceptor =
|
|
||||||
new AsyncRequestInterceptor(getSessionFactory(), sessionHolder);
|
|
||||||
asyncManager.registerCallableInterceptor(participateAttributeName, asyncRequestInterceptor);
|
|
||||||
asyncManager.registerDeferredResultInterceptor(participateAttributeName, asyncRequestInterceptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postHandle(WebRequest request, ModelMap model) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unbind the Hibernate {@code Session} from the thread and close it).
|
|
||||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void afterCompletion(WebRequest request, Exception ex) throws DataAccessException {
|
|
||||||
if (!decrementParticipateCount(request)) {
|
|
||||||
SessionHolder sessionHolder =
|
|
||||||
(SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
|
||||||
logger.debug("Closing Hibernate Session in OpenSessionInViewInterceptor");
|
|
||||||
SessionFactoryUtils.closeSession(sessionHolder.getSession());
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean decrementParticipateCount(WebRequest request) {
|
|
||||||
String participateAttributeName = getParticipateAttributeName();
|
|
||||||
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
|
|
||||||
if (count == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Do not modify the Session: just clear the marker.
|
|
||||||
if (count > 1) {
|
|
||||||
request.setAttribute(participateAttributeName, count - 1, WebRequest.SCOPE_REQUEST);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
request.removeAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterConcurrentHandlingStarted(WebRequest request) {
|
|
||||||
if (!decrementParticipateCount(request)) {
|
|
||||||
TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open a Session for the SessionFactory that this interceptor uses.
|
|
||||||
* <p>The default implementation delegates to the {@link SessionFactory#openSession}
|
|
||||||
* method and sets the {@link Session}'s flush mode to "MANUAL".
|
|
||||||
* @return the Session to use
|
|
||||||
* @throws DataAccessResourceFailureException if the Session could not be created
|
|
||||||
* @see org.hibernate.FlushMode#MANUAL
|
|
||||||
*/
|
|
||||||
protected Session openSession() throws DataAccessResourceFailureException {
|
|
||||||
try {
|
|
||||||
Session session = getSessionFactory().openSession();
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the name of the request attribute that identifies that a request is
|
|
||||||
* already intercepted.
|
|
||||||
* <p>The default implementation takes the {@code toString()} representation
|
|
||||||
* of the {@code SessionFactory} instance and appends {@link #PARTICIPATE_SUFFIX}.
|
|
||||||
*/
|
|
||||||
protected String getParticipateAttributeName() {
|
|
||||||
return getSessionFactory().toString() + PARTICIPATE_SUFFIX;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean applySessionBindingInterceptor(WebAsyncManager asyncManager, String key) {
|
|
||||||
if (asyncManager.getCallableInterceptor(key) == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate4.support;
|
|
||||||
|
|
||||||
import org.aopalliance.intercept.MethodInterceptor;
|
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
|
||||||
import org.hibernate.FlushMode;
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
import org.springframework.dao.DataAccessResourceFailureException;
|
|
||||||
import org.springframework.orm.hibernate4.SessionFactoryUtils;
|
|
||||||
import org.springframework.orm.hibernate4.SessionHolder;
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple AOP Alliance {@link MethodInterceptor} implementation that binds a new
|
|
||||||
* Hibernate {@link Session} for each method invocation, if none bound before.
|
|
||||||
*
|
|
||||||
* <p>This is a simple Hibernate Session scoping interceptor along the lines of
|
|
||||||
* {@link OpenSessionInViewInterceptor}, just for use with AOP setup instead of
|
|
||||||
* MVC setup. It opens a new {@link Session} with flush mode "MANUAL" since the
|
|
||||||
* Session is only meant for reading, except when participating in a transaction.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 4.0.2
|
|
||||||
* @see OpenSessionInViewInterceptor
|
|
||||||
* @see OpenSessionInViewFilter
|
|
||||||
* @see org.springframework.orm.hibernate4.HibernateTransactionManager
|
|
||||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
|
||||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
|
||||||
*/
|
|
||||||
public class OpenSessionInterceptor implements MethodInterceptor, InitializingBean {
|
|
||||||
|
|
||||||
private SessionFactory sessionFactory;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Hibernate SessionFactory that should be used to create Hibernate Sessions.
|
|
||||||
*/
|
|
||||||
public void setSessionFactory(SessionFactory sessionFactory) {
|
|
||||||
this.sessionFactory = sessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the Hibernate SessionFactory that should be used to create Hibernate Sessions.
|
|
||||||
*/
|
|
||||||
public SessionFactory getSessionFactory() {
|
|
||||||
return this.sessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterPropertiesSet() {
|
|
||||||
if (getSessionFactory() == null) {
|
|
||||||
throw new IllegalArgumentException("Property 'sessionFactory' is required");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
|
||||||
SessionFactory sf = getSessionFactory();
|
|
||||||
if (!TransactionSynchronizationManager.hasResource(sf)) {
|
|
||||||
// New Session to be bound for the current method's scope...
|
|
||||||
Session session = openSession();
|
|
||||||
try {
|
|
||||||
TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session));
|
|
||||||
return invocation.proceed();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
SessionFactoryUtils.closeSession(session);
|
|
||||||
TransactionSynchronizationManager.unbindResource(sf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Pre-bound Session found -> simply proceed.
|
|
||||||
return invocation.proceed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open a Session for the SessionFactory that this interceptor uses.
|
|
||||||
* <p>The default implementation delegates to the {@link SessionFactory#openSession}
|
|
||||||
* method and sets the {@link Session}'s flush mode to "MANUAL".
|
|
||||||
* @return the Session to use
|
|
||||||
* @throws DataAccessResourceFailureException if the Session could not be created
|
|
||||||
* @see org.hibernate.FlushMode#MANUAL
|
|
||||||
*/
|
|
||||||
protected Session openSession() throws DataAccessResourceFailureException {
|
|
||||||
try {
|
|
||||||
Session session = getSessionFactory().openSession();
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
/**
|
|
||||||
* Classes supporting the {@code org.springframework.orm.hibernate4} package.
|
|
||||||
*/
|
|
||||||
package org.springframework.orm.hibernate4.support;
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,270 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2015 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.jpa.jpa21;
|
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
|
||||||
import javax.persistence.EntityManagerFactory;
|
|
||||||
import javax.persistence.EntityTransaction;
|
|
||||||
import javax.persistence.PersistenceContext;
|
|
||||||
import javax.persistence.PersistenceContextType;
|
|
||||||
import javax.persistence.SynchronizationType;
|
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
|
||||||
import org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor;
|
|
||||||
import org.springframework.transaction.TransactionDefinition;
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
import static org.mockito.BDDMockito.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy of {@link org.springframework.orm.jpa.support.PersistenceContextTransactionTests},
|
|
||||||
* here to be tested against JPA 2.1, including unsynchronized persistence contexts.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 4.1.2
|
|
||||||
*/
|
|
||||||
public class PersistenceContextTransactionTests {
|
|
||||||
|
|
||||||
private EntityManagerFactory factory;
|
|
||||||
|
|
||||||
private EntityManager manager;
|
|
||||||
|
|
||||||
private EntityTransaction tx;
|
|
||||||
|
|
||||||
private TransactionTemplate tt;
|
|
||||||
|
|
||||||
private EntityManagerHoldingBean bean;
|
|
||||||
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() throws Exception {
|
|
||||||
factory = mock(EntityManagerFactory.class);
|
|
||||||
manager = mock(EntityManager.class);
|
|
||||||
tx = mock(EntityTransaction.class);
|
|
||||||
|
|
||||||
JpaTransactionManager tm = new JpaTransactionManager(factory);
|
|
||||||
tt = new TransactionTemplate(tm);
|
|
||||||
|
|
||||||
given(factory.createEntityManager()).willReturn(manager);
|
|
||||||
given(manager.getTransaction()).willReturn(tx);
|
|
||||||
given(manager.isOpen()).willReturn(true);
|
|
||||||
|
|
||||||
bean = new EntityManagerHoldingBean();
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
PersistenceAnnotationBeanPostProcessor pabpp = new PersistenceAnnotationBeanPostProcessor() {
|
|
||||||
@Override
|
|
||||||
protected EntityManagerFactory findEntityManagerFactory(String unitName, String requestingBeanName) {
|
|
||||||
return factory;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pabpp.postProcessPropertyValues(null, null, bean, "bean");
|
|
||||||
|
|
||||||
assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty());
|
|
||||||
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() throws Exception {
|
|
||||||
assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty());
|
|
||||||
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
|
|
||||||
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
|
|
||||||
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionCommitWithSharedEntityManager() {
|
|
||||||
given(manager.getTransaction()).willReturn(tx);
|
|
||||||
|
|
||||||
tt.execute(status -> {
|
|
||||||
bean.sharedEntityManager.flush();
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
verify(tx).commit();
|
|
||||||
verify(manager).flush();
|
|
||||||
verify(manager).close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionCommitWithSharedEntityManagerAndPropagationSupports() {
|
|
||||||
given(manager.isOpen()).willReturn(true);
|
|
||||||
|
|
||||||
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
|
|
||||||
|
|
||||||
tt.execute(status -> {
|
|
||||||
bean.sharedEntityManager.clear();
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
verify(manager).clear();
|
|
||||||
verify(manager).close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionCommitWithExtendedEntityManager() {
|
|
||||||
given(manager.getTransaction()).willReturn(tx);
|
|
||||||
|
|
||||||
tt.execute(status -> {
|
|
||||||
bean.extendedEntityManager.flush();
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
verify(tx, times(2)).commit();
|
|
||||||
verify(manager).flush();
|
|
||||||
verify(manager).close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionCommitWithExtendedEntityManagerAndPropagationSupports() {
|
|
||||||
given(manager.isOpen()).willReturn(true);
|
|
||||||
|
|
||||||
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
|
|
||||||
|
|
||||||
tt.execute(status -> {
|
|
||||||
bean.extendedEntityManager.flush();
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
verify(manager).flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionCommitWithSharedEntityManagerUnsynchronized() {
|
|
||||||
given(manager.getTransaction()).willReturn(tx);
|
|
||||||
|
|
||||||
tt.execute(status -> {
|
|
||||||
bean.sharedEntityManagerUnsynchronized.flush();
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
verify(tx).commit();
|
|
||||||
verify(manager).flush();
|
|
||||||
verify(manager, times(2)).close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionCommitWithSharedEntityManagerUnsynchronizedAndPropagationSupports() {
|
|
||||||
given(manager.isOpen()).willReturn(true);
|
|
||||||
|
|
||||||
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
|
|
||||||
|
|
||||||
tt.execute(status -> {
|
|
||||||
bean.sharedEntityManagerUnsynchronized.clear();
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
verify(manager).clear();
|
|
||||||
verify(manager).close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionCommitWithExtendedEntityManagerUnsynchronized() {
|
|
||||||
given(manager.getTransaction()).willReturn(tx);
|
|
||||||
|
|
||||||
tt.execute(status -> {
|
|
||||||
bean.extendedEntityManagerUnsynchronized.flush();
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
verify(tx).commit();
|
|
||||||
verify(manager).flush();
|
|
||||||
verify(manager).close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionCommitWithExtendedEntityManagerUnsynchronizedAndPropagationSupports() {
|
|
||||||
given(manager.isOpen()).willReturn(true);
|
|
||||||
|
|
||||||
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
|
|
||||||
|
|
||||||
tt.execute(status -> {
|
|
||||||
bean.extendedEntityManagerUnsynchronized.flush();
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
verify(manager).flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionCommitWithSharedEntityManagerUnsynchronizedJoined() {
|
|
||||||
given(manager.getTransaction()).willReturn(tx);
|
|
||||||
|
|
||||||
tt.execute(status -> {
|
|
||||||
bean.sharedEntityManagerUnsynchronized.joinTransaction();
|
|
||||||
bean.sharedEntityManagerUnsynchronized.flush();
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
verify(tx).commit();
|
|
||||||
verify(manager).flush();
|
|
||||||
verify(manager, times(2)).close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionCommitWithExtendedEntityManagerUnsynchronizedJoined() {
|
|
||||||
given(manager.getTransaction()).willReturn(tx);
|
|
||||||
|
|
||||||
tt.execute(status -> {
|
|
||||||
bean.extendedEntityManagerUnsynchronized.joinTransaction();
|
|
||||||
bean.extendedEntityManagerUnsynchronized.flush();
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
verify(tx, times(2)).commit();
|
|
||||||
verify(manager).flush();
|
|
||||||
verify(manager).close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionCommitWithExtendedEntityManagerUnsynchronizedJoinedAndPropagationSupports() {
|
|
||||||
given(manager.isOpen()).willReturn(true);
|
|
||||||
|
|
||||||
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
|
|
||||||
|
|
||||||
tt.execute(status -> {
|
|
||||||
bean.extendedEntityManagerUnsynchronized.joinTransaction();
|
|
||||||
bean.extendedEntityManagerUnsynchronized.flush();
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
verify(manager).flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class EntityManagerHoldingBean {
|
|
||||||
|
|
||||||
@PersistenceContext
|
|
||||||
public EntityManager sharedEntityManager;
|
|
||||||
|
|
||||||
@PersistenceContext(type = PersistenceContextType.EXTENDED)
|
|
||||||
public EntityManager extendedEntityManager;
|
|
||||||
|
|
||||||
@PersistenceContext(synchronization = SynchronizationType.UNSYNCHRONIZED)
|
|
||||||
public EntityManager sharedEntityManagerUnsynchronized;
|
|
||||||
|
|
||||||
@PersistenceContext(type = PersistenceContextType.EXTENDED, synchronization = SynchronizationType.UNSYNCHRONIZED)
|
|
||||||
public EntityManager extendedEntityManagerUnsynchronized;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,166 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2015 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.validation.hibernatevalidator5;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
import javax.validation.constraints.Size;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.BeanCreationException;
|
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
|
||||||
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
|
|
||||||
import org.springframework.context.support.GenericApplicationContext;
|
|
||||||
import org.springframework.tests.sample.beans.TestBean;
|
|
||||||
import org.springframework.validation.beanvalidation.BeanValidationPostProcessor;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy of {@link org.springframework.validation.beanvalidation.BeanValidationPostProcessor},
|
|
||||||
* here to be tested against Hibernate Validator 5.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 4.1
|
|
||||||
*/
|
|
||||||
public class BeanValidationPostProcessorTests {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNotNullConstraint() {
|
|
||||||
GenericApplicationContext ac = new GenericApplicationContext();
|
|
||||||
ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class));
|
|
||||||
ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class));
|
|
||||||
ac.registerBeanDefinition("bean", new RootBeanDefinition(NotNullConstrainedBean.class));
|
|
||||||
try {
|
|
||||||
ac.refresh();
|
|
||||||
fail("Should have thrown BeanCreationException");
|
|
||||||
}
|
|
||||||
catch (BeanCreationException ex) {
|
|
||||||
assertTrue(ex.getRootCause().getMessage().contains("testBean"));
|
|
||||||
assertTrue(ex.getRootCause().getMessage().contains("invalid"));
|
|
||||||
}
|
|
||||||
ac.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNotNullConstraintSatisfied() {
|
|
||||||
GenericApplicationContext ac = new GenericApplicationContext();
|
|
||||||
ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class));
|
|
||||||
ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class));
|
|
||||||
RootBeanDefinition bd = new RootBeanDefinition(NotNullConstrainedBean.class);
|
|
||||||
bd.getPropertyValues().add("testBean", new TestBean());
|
|
||||||
ac.registerBeanDefinition("bean", bd);
|
|
||||||
ac.refresh();
|
|
||||||
ac.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNotNullConstraintAfterInitialization() {
|
|
||||||
GenericApplicationContext ac = new GenericApplicationContext();
|
|
||||||
RootBeanDefinition bvpp = new RootBeanDefinition(BeanValidationPostProcessor.class);
|
|
||||||
bvpp.getPropertyValues().add("afterInitialization", true);
|
|
||||||
ac.registerBeanDefinition("bvpp", bvpp);
|
|
||||||
ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class));
|
|
||||||
ac.registerBeanDefinition("bean", new RootBeanDefinition(AfterInitConstraintBean.class));
|
|
||||||
ac.refresh();
|
|
||||||
ac.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSizeConstraint() {
|
|
||||||
GenericApplicationContext ac = new GenericApplicationContext();
|
|
||||||
ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class));
|
|
||||||
RootBeanDefinition bd = new RootBeanDefinition(NotNullConstrainedBean.class);
|
|
||||||
bd.getPropertyValues().add("testBean", new TestBean());
|
|
||||||
bd.getPropertyValues().add("stringValue", "s");
|
|
||||||
ac.registerBeanDefinition("bean", bd);
|
|
||||||
try {
|
|
||||||
ac.refresh();
|
|
||||||
fail("Should have thrown BeanCreationException");
|
|
||||||
}
|
|
||||||
catch (BeanCreationException ex) {
|
|
||||||
assertTrue(ex.getRootCause().getMessage().contains("stringValue"));
|
|
||||||
assertTrue(ex.getRootCause().getMessage().contains("invalid"));
|
|
||||||
}
|
|
||||||
ac.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSizeConstraintSatisfied() {
|
|
||||||
GenericApplicationContext ac = new GenericApplicationContext();
|
|
||||||
ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class));
|
|
||||||
RootBeanDefinition bd = new RootBeanDefinition(NotNullConstrainedBean.class);
|
|
||||||
bd.getPropertyValues().add("testBean", new TestBean());
|
|
||||||
bd.getPropertyValues().add("stringValue", "ss");
|
|
||||||
ac.registerBeanDefinition("bean", bd);
|
|
||||||
ac.refresh();
|
|
||||||
ac.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class NotNullConstrainedBean {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private TestBean testBean;
|
|
||||||
|
|
||||||
@Size(min = 2)
|
|
||||||
private String stringValue;
|
|
||||||
|
|
||||||
public TestBean getTestBean() {
|
|
||||||
return testBean;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTestBean(TestBean testBean) {
|
|
||||||
this.testBean = testBean;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getStringValue() {
|
|
||||||
return stringValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStringValue(String stringValue) {
|
|
||||||
this.stringValue = stringValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void init() {
|
|
||||||
assertNotNull("Shouldn't be here after constraint checking", this.testBean);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class AfterInitConstraintBean {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private TestBean testBean;
|
|
||||||
|
|
||||||
public TestBean getTestBean() {
|
|
||||||
return testBean;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTestBean(TestBean testBean) {
|
|
||||||
this.testBean = testBean;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void init() {
|
|
||||||
this.testBean = new TestBean();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,173 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2015 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.validation.hibernatevalidator5;
|
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import javax.validation.constraints.Max;
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
import javax.validation.groups.Default;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import org.springframework.aop.framework.ProxyFactory;
|
|
||||||
import org.springframework.beans.MutablePropertyValues;
|
|
||||||
import org.springframework.context.support.StaticApplicationContext;
|
|
||||||
import org.springframework.scheduling.annotation.Async;
|
|
||||||
import org.springframework.scheduling.annotation.AsyncAnnotationAdvisor;
|
|
||||||
import org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.validation.beanvalidation.MethodValidationInterceptor;
|
|
||||||
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy of {@link org.springframework.validation.beanvalidation.MethodValidationTests},
|
|
||||||
* here to be tested against Hibernate Validator 5.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 4.1
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
public class MethodValidationTests {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testMethodValidationInterceptor() {
|
|
||||||
MyValidBean bean = new MyValidBean();
|
|
||||||
ProxyFactory proxyFactory = new ProxyFactory(bean);
|
|
||||||
proxyFactory.addAdvice(new MethodValidationInterceptor());
|
|
||||||
proxyFactory.addAdvisor(new AsyncAnnotationAdvisor());
|
|
||||||
doTestProxyValidation((MyValidInterface) proxyFactory.getProxy());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testMethodValidationPostProcessor() {
|
|
||||||
StaticApplicationContext ac = new StaticApplicationContext();
|
|
||||||
ac.registerSingleton("mvpp", MethodValidationPostProcessor.class);
|
|
||||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
|
||||||
pvs.add("beforeExistingAdvisors", false);
|
|
||||||
ac.registerSingleton("aapp", AsyncAnnotationBeanPostProcessor.class, pvs);
|
|
||||||
ac.registerSingleton("bean", MyValidBean.class);
|
|
||||||
ac.refresh();
|
|
||||||
doTestProxyValidation(ac.getBean("bean", MyValidInterface.class));
|
|
||||||
ac.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private void doTestProxyValidation(MyValidInterface proxy) {
|
|
||||||
assertNotNull(proxy.myValidMethod("value", 5));
|
|
||||||
try {
|
|
||||||
assertNotNull(proxy.myValidMethod("value", 15));
|
|
||||||
fail("Should have thrown ValidationException");
|
|
||||||
}
|
|
||||||
catch (javax.validation.ValidationException ex) {
|
|
||||||
// expected
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
assertNotNull(proxy.myValidMethod(null, 5));
|
|
||||||
fail("Should have thrown ValidationException");
|
|
||||||
}
|
|
||||||
catch (javax.validation.ValidationException ex) {
|
|
||||||
// expected
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
assertNotNull(proxy.myValidMethod("value", 0));
|
|
||||||
fail("Should have thrown ValidationException");
|
|
||||||
}
|
|
||||||
catch (javax.validation.ValidationException ex) {
|
|
||||||
// expected
|
|
||||||
}
|
|
||||||
|
|
||||||
proxy.myValidAsyncMethod("value", 5);
|
|
||||||
try {
|
|
||||||
proxy.myValidAsyncMethod("value", 15);
|
|
||||||
fail("Should have thrown ValidationException");
|
|
||||||
}
|
|
||||||
catch (javax.validation.ValidationException ex) {
|
|
||||||
// expected
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
proxy.myValidAsyncMethod(null, 5);
|
|
||||||
fail("Should have thrown ValidationException");
|
|
||||||
}
|
|
||||||
catch (javax.validation.ValidationException ex) {
|
|
||||||
// expected
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals("myValue", proxy.myGenericMethod("myValue"));
|
|
||||||
try {
|
|
||||||
proxy.myGenericMethod(null);
|
|
||||||
fail("Should have thrown ValidationException");
|
|
||||||
}
|
|
||||||
catch (javax.validation.ValidationException ex) {
|
|
||||||
// expected
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@MyStereotype
|
|
||||||
public static class MyValidBean implements MyValidInterface<String> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object myValidMethod(String arg1, int arg2) {
|
|
||||||
return (arg2 == 0 ? null : "value");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void myValidAsyncMethod(String arg1, int arg2) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String myGenericMethod(String value) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public interface MyValidInterface<T> {
|
|
||||||
|
|
||||||
@NotNull Object myValidMethod(@NotNull(groups = MyGroup.class) String arg1, @Max(10) int arg2);
|
|
||||||
|
|
||||||
@MyValid
|
|
||||||
@Async void myValidAsyncMethod(@NotNull(groups = OtherGroup.class) String arg1, @Max(10) int arg2);
|
|
||||||
|
|
||||||
T myGenericMethod(@NotNull T value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public interface MyGroup {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public interface OtherGroup {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Validated({MyGroup.class, Default.class})
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface MyStereotype {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Validated({OtherGroup.class, Default.class})
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface MyValid {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,430 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2015 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.validation.hibernatevalidator5;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
|
||||||
import javax.validation.Constraint;
|
|
||||||
import javax.validation.ConstraintValidator;
|
|
||||||
import javax.validation.ConstraintValidatorContext;
|
|
||||||
import javax.validation.ConstraintViolation;
|
|
||||||
import javax.validation.Payload;
|
|
||||||
import javax.validation.Valid;
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
|
|
||||||
import org.hibernate.validator.HibernateValidator;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
|
||||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.validation.BeanPropertyBindingResult;
|
|
||||||
import org.springframework.validation.Errors;
|
|
||||||
import org.springframework.validation.FieldError;
|
|
||||||
import org.springframework.validation.ObjectError;
|
|
||||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy of {@link org.springframework.validation.beanvalidation.ValidatorFactoryTests},
|
|
||||||
* here to be tested against Hibernate Validator 5.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 4.1
|
|
||||||
*/
|
|
||||||
public class ValidatorFactoryTests {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSimpleValidation() throws Exception {
|
|
||||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
|
||||||
validator.afterPropertiesSet();
|
|
||||||
|
|
||||||
ValidPerson person = new ValidPerson();
|
|
||||||
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person);
|
|
||||||
assertEquals(2, result.size());
|
|
||||||
for (ConstraintViolation<ValidPerson> cv : result) {
|
|
||||||
String path = cv.getPropertyPath().toString();
|
|
||||||
if ("name".equals(path) || "address.street".equals(path)) {
|
|
||||||
assertTrue(cv.getConstraintDescriptor().getAnnotation() instanceof NotNull);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fail("Invalid constraint violation with path '" + path + "'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
validator.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSimpleValidationWithCustomProvider() throws Exception {
|
|
||||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
|
||||||
validator.setProviderClass(HibernateValidator.class);
|
|
||||||
validator.afterPropertiesSet();
|
|
||||||
|
|
||||||
ValidPerson person = new ValidPerson();
|
|
||||||
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person);
|
|
||||||
assertEquals(2, result.size());
|
|
||||||
for (ConstraintViolation<ValidPerson> cv : result) {
|
|
||||||
String path = cv.getPropertyPath().toString();
|
|
||||||
if ("name".equals(path) || "address.street".equals(path)) {
|
|
||||||
assertTrue(cv.getConstraintDescriptor().getAnnotation() instanceof NotNull);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fail("Invalid constraint violation with path '" + path + "'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
validator.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSimpleValidationWithClassLevel() throws Exception {
|
|
||||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
|
||||||
validator.afterPropertiesSet();
|
|
||||||
ValidPerson person = new ValidPerson();
|
|
||||||
person.setName("Juergen");
|
|
||||||
person.getAddress().setStreet("Juergen's Street");
|
|
||||||
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person);
|
|
||||||
assertEquals(1, result.size());
|
|
||||||
Iterator<ConstraintViolation<ValidPerson>> iterator = result.iterator();
|
|
||||||
ConstraintViolation<?> cv = iterator.next();
|
|
||||||
assertEquals("", cv.getPropertyPath().toString());
|
|
||||||
assertTrue(cv.getConstraintDescriptor().getAnnotation() instanceof NameAddressValid);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSpringValidationFieldType() throws Exception {
|
|
||||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
|
||||||
validator.afterPropertiesSet();
|
|
||||||
|
|
||||||
ValidPerson person = new ValidPerson();
|
|
||||||
person.setName("Phil");
|
|
||||||
person.getAddress().setStreet("Phil's Street");
|
|
||||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(person, "person");
|
|
||||||
validator.validate(person, errors);
|
|
||||||
assertEquals(1, errors.getErrorCount());
|
|
||||||
assertThat("Field/Value type mismatch", errors.getFieldError("address").getRejectedValue(),
|
|
||||||
instanceOf(ValidAddress.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSpringValidation() throws Exception {
|
|
||||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
|
||||||
validator.afterPropertiesSet();
|
|
||||||
|
|
||||||
ValidPerson person = new ValidPerson();
|
|
||||||
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
|
|
||||||
validator.validate(person, result);
|
|
||||||
assertEquals(2, result.getErrorCount());
|
|
||||||
FieldError fieldError = result.getFieldError("name");
|
|
||||||
assertEquals("name", fieldError.getField());
|
|
||||||
List<String> errorCodes = Arrays.asList(fieldError.getCodes());
|
|
||||||
assertEquals(4, errorCodes.size());
|
|
||||||
assertTrue(errorCodes.contains("NotNull.person.name"));
|
|
||||||
assertTrue(errorCodes.contains("NotNull.name"));
|
|
||||||
assertTrue(errorCodes.contains("NotNull.java.lang.String"));
|
|
||||||
assertTrue(errorCodes.contains("NotNull"));
|
|
||||||
fieldError = result.getFieldError("address.street");
|
|
||||||
assertEquals("address.street", fieldError.getField());
|
|
||||||
errorCodes = Arrays.asList(fieldError.getCodes());
|
|
||||||
assertEquals(5, errorCodes.size());
|
|
||||||
assertTrue(errorCodes.contains("NotNull.person.address.street"));
|
|
||||||
assertTrue(errorCodes.contains("NotNull.address.street"));
|
|
||||||
assertTrue(errorCodes.contains("NotNull.street"));
|
|
||||||
assertTrue(errorCodes.contains("NotNull.java.lang.String"));
|
|
||||||
assertTrue(errorCodes.contains("NotNull"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSpringValidationWithClassLevel() throws Exception {
|
|
||||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
|
||||||
validator.afterPropertiesSet();
|
|
||||||
|
|
||||||
ValidPerson person = new ValidPerson();
|
|
||||||
person.setName("Juergen");
|
|
||||||
person.getAddress().setStreet("Juergen's Street");
|
|
||||||
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
|
|
||||||
validator.validate(person, result);
|
|
||||||
assertEquals(1, result.getErrorCount());
|
|
||||||
ObjectError globalError = result.getGlobalError();
|
|
||||||
List<String> errorCodes = Arrays.asList(globalError.getCodes());
|
|
||||||
assertEquals(2, errorCodes.size());
|
|
||||||
assertTrue(errorCodes.contains("NameAddressValid.person"));
|
|
||||||
assertTrue(errorCodes.contains("NameAddressValid"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSpringValidationWithAutowiredValidator() throws Exception {
|
|
||||||
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(
|
|
||||||
LocalValidatorFactoryBean.class);
|
|
||||||
LocalValidatorFactoryBean validator = ctx.getBean(LocalValidatorFactoryBean.class);
|
|
||||||
|
|
||||||
ValidPerson person = new ValidPerson();
|
|
||||||
person.expectsAutowiredValidator = true;
|
|
||||||
person.setName("Juergen");
|
|
||||||
person.getAddress().setStreet("Juergen's Street");
|
|
||||||
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
|
|
||||||
validator.validate(person, result);
|
|
||||||
assertEquals(1, result.getErrorCount());
|
|
||||||
ObjectError globalError = result.getGlobalError();
|
|
||||||
List<String> errorCodes = Arrays.asList(globalError.getCodes());
|
|
||||||
assertEquals(2, errorCodes.size());
|
|
||||||
assertTrue(errorCodes.contains("NameAddressValid.person"));
|
|
||||||
assertTrue(errorCodes.contains("NameAddressValid"));
|
|
||||||
ctx.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSpringValidationWithErrorInListElement() throws Exception {
|
|
||||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
|
||||||
validator.afterPropertiesSet();
|
|
||||||
|
|
||||||
ValidPerson person = new ValidPerson();
|
|
||||||
person.getAddressList().add(new ValidAddress());
|
|
||||||
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
|
|
||||||
validator.validate(person, result);
|
|
||||||
assertEquals(3, result.getErrorCount());
|
|
||||||
FieldError fieldError = result.getFieldError("name");
|
|
||||||
assertEquals("name", fieldError.getField());
|
|
||||||
fieldError = result.getFieldError("address.street");
|
|
||||||
assertEquals("address.street", fieldError.getField());
|
|
||||||
fieldError = result.getFieldError("addressList[0].street");
|
|
||||||
assertEquals("addressList[0].street", fieldError.getField());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSpringValidationWithErrorInSetElement() throws Exception {
|
|
||||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
|
||||||
validator.afterPropertiesSet();
|
|
||||||
|
|
||||||
ValidPerson person = new ValidPerson();
|
|
||||||
person.getAddressSet().add(new ValidAddress());
|
|
||||||
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
|
|
||||||
validator.validate(person, result);
|
|
||||||
assertEquals(3, result.getErrorCount());
|
|
||||||
FieldError fieldError = result.getFieldError("name");
|
|
||||||
assertEquals("name", fieldError.getField());
|
|
||||||
fieldError = result.getFieldError("address.street");
|
|
||||||
assertEquals("address.street", fieldError.getField());
|
|
||||||
fieldError = result.getFieldError("addressSet[].street");
|
|
||||||
assertEquals("addressSet[].street", fieldError.getField());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testInnerBeanValidation() throws Exception {
|
|
||||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
|
||||||
validator.afterPropertiesSet();
|
|
||||||
|
|
||||||
MainBean mainBean = new MainBean();
|
|
||||||
Errors errors = new BeanPropertyBindingResult(mainBean, "mainBean");
|
|
||||||
validator.validate(mainBean, errors);
|
|
||||||
Object rejected = errors.getFieldValue("inner.value");
|
|
||||||
assertNull(rejected);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testValidationWithOptionalField() throws Exception {
|
|
||||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
|
||||||
validator.afterPropertiesSet();
|
|
||||||
|
|
||||||
MainBeanWithOptional mainBean = new MainBeanWithOptional();
|
|
||||||
Errors errors = new BeanPropertyBindingResult(mainBean, "mainBean");
|
|
||||||
validator.validate(mainBean, errors);
|
|
||||||
Object rejected = errors.getFieldValue("inner.value");
|
|
||||||
assertNull(rejected);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@NameAddressValid
|
|
||||||
public static class ValidPerson {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@Valid
|
|
||||||
private ValidAddress address = new ValidAddress();
|
|
||||||
|
|
||||||
@Valid
|
|
||||||
private List<ValidAddress> addressList = new LinkedList<ValidAddress>();
|
|
||||||
|
|
||||||
@Valid
|
|
||||||
private Set<ValidAddress> addressSet = new LinkedHashSet<ValidAddress>();
|
|
||||||
|
|
||||||
public boolean expectsAutowiredValidator = false;
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValidAddress getAddress() {
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAddress(ValidAddress address) {
|
|
||||||
this.address = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ValidAddress> getAddressList() {
|
|
||||||
return addressList;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAddressList(List<ValidAddress> addressList) {
|
|
||||||
this.addressList = addressList;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<ValidAddress> getAddressSet() {
|
|
||||||
return addressSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAddressSet(Set<ValidAddress> addressSet) {
|
|
||||||
this.addressSet = addressSet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class ValidAddress {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private String street;
|
|
||||||
|
|
||||||
public String getStreet() {
|
|
||||||
return street;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStreet(String street) {
|
|
||||||
this.street = street;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Target(ElementType.TYPE)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Constraint(validatedBy = NameAddressValidator.class)
|
|
||||||
public @interface NameAddressValid {
|
|
||||||
|
|
||||||
String message() default "Street must not contain name";
|
|
||||||
|
|
||||||
Class<?>[] groups() default {};
|
|
||||||
|
|
||||||
Class<?>[] payload() default {};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class NameAddressValidator implements ConstraintValidator<NameAddressValid, ValidPerson> {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private Environment environment;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(NameAddressValid constraintAnnotation) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValid(ValidPerson value, ConstraintValidatorContext context) {
|
|
||||||
if (value.expectsAutowiredValidator) {
|
|
||||||
assertNotNull(this.environment);
|
|
||||||
}
|
|
||||||
boolean valid = (value.name == null || !value.address.street.contains(value.name));
|
|
||||||
if (!valid && "Phil".equals(value.name)) {
|
|
||||||
context.buildConstraintViolationWithTemplate(
|
|
||||||
context.getDefaultConstraintMessageTemplate()).addPropertyNode("address").addConstraintViolation().disableDefaultConstraintViolation();
|
|
||||||
}
|
|
||||||
return valid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class MainBean {
|
|
||||||
|
|
||||||
@InnerValid
|
|
||||||
private InnerBean inner = new InnerBean();
|
|
||||||
|
|
||||||
public InnerBean getInner() {
|
|
||||||
return inner;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class MainBeanWithOptional {
|
|
||||||
|
|
||||||
@InnerValid
|
|
||||||
private InnerBean inner = new InnerBean();
|
|
||||||
|
|
||||||
public Optional<InnerBean> getInner() {
|
|
||||||
return Optional.ofNullable(inner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class InnerBean {
|
|
||||||
|
|
||||||
private String value;
|
|
||||||
|
|
||||||
public String getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
public void setValue(String value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target(ElementType.FIELD)
|
|
||||||
@Constraint(validatedBy=InnerValidator.class)
|
|
||||||
public static @interface InnerValid {
|
|
||||||
|
|
||||||
String message() default "NOT VALID";
|
|
||||||
|
|
||||||
Class<?>[] groups() default { };
|
|
||||||
|
|
||||||
Class<? extends Payload>[] payload() default {};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class InnerValidator implements ConstraintValidator<InnerValid, InnerBean> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(InnerValid constraintAnnotation) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValid(InnerBean bean, ConstraintValidatorContext context) {
|
|
||||||
context.disableDefaultConstraintViolation();
|
|
||||||
if (bean.getValue() == null) {
|
|
||||||
context.buildConstraintViolationWithTemplate("NULL").addPropertyNode("value").addConstraintViolation();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
log4j.appender.console=org.apache.log4j.ConsoleAppender
|
|
||||||
log4j.appender.console.layout=org.apache.log4j.PatternLayout
|
|
||||||
log4j.appender.console.layout.ConversionPattern=%d{HH:mm:ss,SSS} [%c] - %m%n
|
|
||||||
|
|
||||||
log4j.rootCategory=WARN, console
|
|
||||||
log4j.logger.org.springframework.beans=WARN
|
|
||||||
log4j.logger.org.springframework.binding=DEBUG
|
|
||||||
|
|
||||||
#log4j.logger.org.springframework.orm.hibernate4=TRACE
|
|
||||||
|
|
||||||
|
|
@ -1,285 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.DisposableBean;
|
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract {@link org.springframework.beans.factory.FactoryBean} that creates
|
|
||||||
* a Hibernate {@link org.hibernate.SessionFactory} within a Spring application
|
|
||||||
* context, providing general infrastructure not related to Hibernate's
|
|
||||||
* specific configuration API.
|
|
||||||
*
|
|
||||||
* <p>This class implements the
|
|
||||||
* {@link org.springframework.dao.support.PersistenceExceptionTranslator}
|
|
||||||
* interface, as autodetected by Spring's
|
|
||||||
* {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor},
|
|
||||||
* for AOP-based translation of native exceptions to Spring DataAccessExceptions.
|
|
||||||
* Hence, the presence of e.g. LocalSessionFactoryBean automatically enables
|
|
||||||
* a PersistenceExceptionTranslationPostProcessor to translate Hibernate exceptions.
|
|
||||||
*
|
|
||||||
* <p>This class mainly serves as common base class for {@link LocalSessionFactoryBean}.
|
|
||||||
* For details on typical SessionFactory setup, see the LocalSessionFactoryBean javadoc.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 2.0
|
|
||||||
* @see #setExposeTransactionAwareSessionFactory
|
|
||||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
|
||||||
* @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public abstract class AbstractSessionFactoryBean extends HibernateExceptionTranslator
|
|
||||||
implements FactoryBean<SessionFactory>, InitializingBean, DisposableBean {
|
|
||||||
|
|
||||||
/** Logger available to subclasses */
|
|
||||||
protected final Log logger = LogFactory.getLog(getClass());
|
|
||||||
|
|
||||||
private DataSource dataSource;
|
|
||||||
|
|
||||||
private boolean useTransactionAwareDataSource = false;
|
|
||||||
|
|
||||||
private boolean exposeTransactionAwareSessionFactory = true;
|
|
||||||
|
|
||||||
private SessionFactory sessionFactory;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the DataSource to be used by the SessionFactory.
|
|
||||||
* If set, this will override corresponding settings in Hibernate properties.
|
|
||||||
* <p>If this is set, the Hibernate settings should not define
|
|
||||||
* a connection provider to avoid meaningless double configuration.
|
|
||||||
* <p>If using HibernateTransactionManager as transaction strategy, consider
|
|
||||||
* proxying your target DataSource with a LazyConnectionDataSourceProxy.
|
|
||||||
* This defers fetching of an actual JDBC Connection until the first JDBC
|
|
||||||
* Statement gets executed, even within JDBC transactions (as performed by
|
|
||||||
* HibernateTransactionManager). Such lazy fetching is particularly beneficial
|
|
||||||
* for read-only operations, in particular if the chances of resolving the
|
|
||||||
* result in the second-level cache are high.
|
|
||||||
* <p>As JTA and transactional JNDI DataSources already provide lazy enlistment
|
|
||||||
* of JDBC Connections, LazyConnectionDataSourceProxy does not add value with
|
|
||||||
* JTA (i.e. Spring's JtaTransactionManager) as transaction strategy.
|
|
||||||
* @see #setUseTransactionAwareDataSource
|
|
||||||
* @see HibernateTransactionManager
|
|
||||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
|
||||||
* @see org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy
|
|
||||||
*/
|
|
||||||
public void setDataSource(DataSource dataSource) {
|
|
||||||
this.dataSource = dataSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the DataSource to be used by the SessionFactory.
|
|
||||||
*/
|
|
||||||
public DataSource getDataSource() {
|
|
||||||
return this.dataSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether to use a transaction-aware DataSource for the SessionFactory,
|
|
||||||
* i.e. whether to automatically wrap the passed-in DataSource with Spring's
|
|
||||||
* TransactionAwareDataSourceProxy.
|
|
||||||
* <p>Default is "false": LocalSessionFactoryBean is usually used with Spring's
|
|
||||||
* HibernateTransactionManager or JtaTransactionManager, both of which work nicely
|
|
||||||
* on a plain JDBC DataSource. Hibernate Sessions and their JDBC Connections are
|
|
||||||
* fully managed by the Hibernate/JTA transaction infrastructure in such a scenario.
|
|
||||||
* <p>If you switch this flag to "true", Spring's Hibernate access will be able to
|
|
||||||
* <i>participate in JDBC-based transactions managed outside of Hibernate</i>
|
|
||||||
* (for example, by Spring's DataSourceTransactionManager). This can be convenient
|
|
||||||
* if you need a different local transaction strategy for another O/R mapping tool,
|
|
||||||
* for example, but still want Hibernate access to join into those transactions.
|
|
||||||
* <p>A further benefit of this option is that <i>plain Sessions opened directly
|
|
||||||
* via the SessionFactory</i>, outside of Spring's Hibernate support, will still
|
|
||||||
* participate in active Spring-managed transactions. However, consider using
|
|
||||||
* Hibernate's {@code getCurrentSession()} method instead (see javadoc of
|
|
||||||
* "exposeTransactionAwareSessionFactory" property).
|
|
||||||
* <p><b>WARNING:</b> When using a transaction-aware JDBC DataSource in combination
|
|
||||||
* with OpenSessionInViewFilter/Interceptor, whether participating in JTA or
|
|
||||||
* external JDBC-based transactions, it is strongly recommended to set Hibernate's
|
|
||||||
* Connection release mode to "after_transaction" or "after_statement", which
|
|
||||||
* guarantees proper Connection handling in such a scenario. In contrast to that,
|
|
||||||
* HibernateTransactionManager generally requires release mode "on_close".
|
|
||||||
* <p>Note: If you want to use Hibernate's Connection release mode "after_statement"
|
|
||||||
* with a DataSource specified on this LocalSessionFactoryBean (for example, a
|
|
||||||
* JTA-aware DataSource fetched from JNDI), switch this setting to "true".
|
|
||||||
* Otherwise, the ConnectionProvider used underneath will vote against aggressive
|
|
||||||
* release and thus silently switch to release mode "after_transaction".
|
|
||||||
* @see #setDataSource
|
|
||||||
* @see #setExposeTransactionAwareSessionFactory
|
|
||||||
* @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
|
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
|
|
||||||
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
|
|
||||||
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
|
|
||||||
* @see HibernateTransactionManager
|
|
||||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
|
||||||
*/
|
|
||||||
public void setUseTransactionAwareDataSource(boolean useTransactionAwareDataSource) {
|
|
||||||
this.useTransactionAwareDataSource = useTransactionAwareDataSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return whether to use a transaction-aware DataSource for the SessionFactory.
|
|
||||||
*/
|
|
||||||
protected boolean isUseTransactionAwareDataSource() {
|
|
||||||
return this.useTransactionAwareDataSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether to expose a transaction-aware current Session from the
|
|
||||||
* SessionFactory's {@code getCurrentSession()} method, returning the
|
|
||||||
* Session that's associated with the current Spring-managed transaction, if any.
|
|
||||||
* <p>Default is "true", letting data access code work with the plain
|
|
||||||
* Hibernate SessionFactory and its {@code getCurrentSession()} method,
|
|
||||||
* while still being able to participate in current Spring-managed transactions:
|
|
||||||
* with any transaction management strategy, either local or JTA / EJB CMT,
|
|
||||||
* and any transaction synchronization mechanism, either Spring or JTA.
|
|
||||||
* Furthermore, {@code getCurrentSession()} will also seamlessly work with
|
|
||||||
* a request-scoped Session managed by OpenSessionInViewFilter/Interceptor.
|
|
||||||
* <p>Turn this flag off to expose the plain Hibernate SessionFactory with
|
|
||||||
* Hibernate's default {@code getCurrentSession()} behavior, supporting
|
|
||||||
* plain JTA synchronization only. Alternatively, simply override the
|
|
||||||
* corresponding Hibernate property "hibernate.current_session_context_class".
|
|
||||||
* @see SpringSessionContext
|
|
||||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
|
||||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
|
||||||
* @see HibernateTransactionManager
|
|
||||||
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
|
|
||||||
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
|
|
||||||
*/
|
|
||||||
public void setExposeTransactionAwareSessionFactory(boolean exposeTransactionAwareSessionFactory) {
|
|
||||||
this.exposeTransactionAwareSessionFactory = exposeTransactionAwareSessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return whether to expose a transaction-aware proxy for the SessionFactory.
|
|
||||||
*/
|
|
||||||
protected boolean isExposeTransactionAwareSessionFactory() {
|
|
||||||
return this.exposeTransactionAwareSessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build and expose the SessionFactory.
|
|
||||||
* @see #buildSessionFactory()
|
|
||||||
* @see #wrapSessionFactoryIfNecessary
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void afterPropertiesSet() throws Exception {
|
|
||||||
SessionFactory rawSf = buildSessionFactory();
|
|
||||||
this.sessionFactory = wrapSessionFactoryIfNecessary(rawSf);
|
|
||||||
afterSessionFactoryCreation();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrap the given SessionFactory with a proxy, if demanded.
|
|
||||||
* <p>The default implementation simply returns the given SessionFactory as-is.
|
|
||||||
* Subclasses may override this to implement transaction awareness through
|
|
||||||
* a SessionFactory proxy, for example.
|
|
||||||
* @param rawSf the raw SessionFactory as built by {@link #buildSessionFactory()}
|
|
||||||
* @return the SessionFactory reference to expose
|
|
||||||
* @see #buildSessionFactory()
|
|
||||||
*/
|
|
||||||
protected SessionFactory wrapSessionFactoryIfNecessary(SessionFactory rawSf) {
|
|
||||||
return rawSf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the exposed SessionFactory.
|
|
||||||
* Will throw an exception if not initialized yet.
|
|
||||||
* @return the SessionFactory (never {@code null})
|
|
||||||
* @throws IllegalStateException if the SessionFactory has not been initialized yet
|
|
||||||
*/
|
|
||||||
protected final SessionFactory getSessionFactory() {
|
|
||||||
if (this.sessionFactory == null) {
|
|
||||||
throw new IllegalStateException("SessionFactory not initialized yet");
|
|
||||||
}
|
|
||||||
return this.sessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the SessionFactory on bean factory shutdown.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void destroy() throws HibernateException {
|
|
||||||
logger.info("Closing Hibernate SessionFactory");
|
|
||||||
try {
|
|
||||||
beforeSessionFactoryDestruction();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
this.sessionFactory.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the singleton SessionFactory.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public SessionFactory getObject() {
|
|
||||||
return this.sessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<? extends SessionFactory> getObjectType() {
|
|
||||||
return (this.sessionFactory != null ? this.sessionFactory.getClass() : SessionFactory.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSingleton() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build the underlying Hibernate SessionFactory.
|
|
||||||
* @return the raw SessionFactory (potentially to be wrapped with a
|
|
||||||
* transaction-aware proxy before it is exposed to the application)
|
|
||||||
* @throws Exception in case of initialization failure
|
|
||||||
*/
|
|
||||||
protected abstract SessionFactory buildSessionFactory() throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook that allows post-processing after the SessionFactory has been
|
|
||||||
* successfully created. The SessionFactory is already available through
|
|
||||||
* {@code getSessionFactory()} at this point.
|
|
||||||
* <p>This implementation is empty.
|
|
||||||
* @throws Exception in case of initialization failure
|
|
||||||
* @see #getSessionFactory()
|
|
||||||
*/
|
|
||||||
protected void afterSessionFactoryCreation() throws Exception {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook that allows shutdown processing before the SessionFactory
|
|
||||||
* will be closed. The SessionFactory is still available through
|
|
||||||
* {@code getSessionFactory()} at this point.
|
|
||||||
* <p>This implementation is empty.
|
|
||||||
* @see #getSessionFactory()
|
|
||||||
*/
|
|
||||||
protected void beforeSessionFactoryDestruction() {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,145 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2013 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.hibernate.engine.FilterDefinition;
|
|
||||||
import org.hibernate.type.Type;
|
|
||||||
import org.hibernate.type.TypeResolver;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.BeanNameAware;
|
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenient FactoryBean for defining Hibernate FilterDefinitions.
|
|
||||||
* Exposes a corresponding Hibernate FilterDefinition object.
|
|
||||||
*
|
|
||||||
* <p>Typically defined as an inner bean within a LocalSessionFactoryBean
|
|
||||||
* definition, as the list element for the "filterDefinitions" bean property.
|
|
||||||
* For example:
|
|
||||||
*
|
|
||||||
* <pre class="code">
|
|
||||||
* <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
|
|
||||||
* ...
|
|
||||||
* <property name="filterDefinitions">
|
|
||||||
* <list>
|
|
||||||
* <bean class="org.springframework.orm.hibernate3.FilterDefinitionFactoryBean">
|
|
||||||
* <property name="filterName" value="myFilter"/>
|
|
||||||
* <property name="parameterTypes">
|
|
||||||
* <map>
|
|
||||||
* <entry key="myParam" value="string"/>
|
|
||||||
* <entry key="myOtherParam" value="long"/>
|
|
||||||
* </map>
|
|
||||||
* </property>
|
|
||||||
* </bean>
|
|
||||||
* </list>
|
|
||||||
* </property>
|
|
||||||
* ...
|
|
||||||
* </bean></pre>
|
|
||||||
*
|
|
||||||
* Alternatively, specify a bean id (or name) attribute for the inner bean,
|
|
||||||
* instead of the "filterName" property.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see org.hibernate.engine.FilterDefinition
|
|
||||||
* @see LocalSessionFactoryBean#setFilterDefinitions
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class FilterDefinitionFactoryBean implements FactoryBean<FilterDefinition>, BeanNameAware, InitializingBean {
|
|
||||||
|
|
||||||
private final TypeResolver typeResolver = new TypeResolver();
|
|
||||||
|
|
||||||
private String filterName;
|
|
||||||
|
|
||||||
private Map<String, Type> parameterTypeMap = new HashMap<String, Type>();
|
|
||||||
|
|
||||||
private String defaultFilterCondition;
|
|
||||||
|
|
||||||
private FilterDefinition filterDefinition;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the name of the filter.
|
|
||||||
*/
|
|
||||||
public void setFilterName(String filterName) {
|
|
||||||
this.filterName = filterName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the parameter types for the filter,
|
|
||||||
* with parameter names as keys and type names as values.
|
|
||||||
* See {@code org.hibernate.type.TypeResolver#heuristicType(String)}.
|
|
||||||
*/
|
|
||||||
public void setParameterTypes(Map<String, String> parameterTypes) {
|
|
||||||
if (parameterTypes != null) {
|
|
||||||
this.parameterTypeMap = new HashMap<String, Type>(parameterTypes.size());
|
|
||||||
for (Map.Entry<String, String> entry : parameterTypes.entrySet()) {
|
|
||||||
this.parameterTypeMap.put(entry.getKey(), this.typeResolver.heuristicType(entry.getValue()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.parameterTypeMap = new HashMap<String, Type>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify a default filter condition for the filter, if any.
|
|
||||||
*/
|
|
||||||
public void setDefaultFilterCondition(String defaultFilterCondition) {
|
|
||||||
this.defaultFilterCondition = defaultFilterCondition;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If no explicit filter name has been specified, the bean name of
|
|
||||||
* the FilterDefinitionFactoryBean will be used.
|
|
||||||
* @see #setFilterName
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void setBeanName(String name) {
|
|
||||||
if (this.filterName == null) {
|
|
||||||
this.filterName = name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterPropertiesSet() {
|
|
||||||
this.filterDefinition =
|
|
||||||
new FilterDefinition(this.filterName, this.defaultFilterCondition, this.parameterTypeMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FilterDefinition getObject() {
|
|
||||||
return this.filterDefinition;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<FilterDefinition> getObjectType() {
|
|
||||||
return FilterDefinition.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSingleton() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,492 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.hibernate.FlushMode;
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.Interceptor;
|
|
||||||
import org.hibernate.JDBCException;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
import org.hibernate.exception.GenericJDBCException;
|
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
|
||||||
import org.springframework.beans.factory.BeanFactoryAware;
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
import org.springframework.core.Constants;
|
|
||||||
import org.springframework.dao.DataAccessException;
|
|
||||||
import org.springframework.jdbc.support.SQLExceptionTranslator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for {@link HibernateTemplate} and {@link HibernateInterceptor},
|
|
||||||
* defining common properties such as SessionFactory and flushing behavior.
|
|
||||||
*
|
|
||||||
* <p>Not intended to be used directly.
|
|
||||||
* See {@link HibernateTemplate} and {@link HibernateInterceptor}.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see HibernateTemplate
|
|
||||||
* @see HibernateInterceptor
|
|
||||||
* @see #setFlushMode
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public abstract class HibernateAccessor implements InitializingBean, BeanFactoryAware {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Never flush is a good strategy for read-only units of work.
|
|
||||||
* Hibernate will not track and look for changes in this case,
|
|
||||||
* avoiding any overhead of modification detection.
|
|
||||||
* <p>In case of an existing Session, FLUSH_NEVER will turn the flush mode
|
|
||||||
* to NEVER for the scope of the current operation, resetting the previous
|
|
||||||
* flush mode afterwards.
|
|
||||||
* @see #setFlushMode
|
|
||||||
*/
|
|
||||||
public static final int FLUSH_NEVER = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Automatic flushing is the default mode for a Hibernate Session.
|
|
||||||
* A session will get flushed on transaction commit, and on certain find
|
|
||||||
* operations that might involve already modified instances, but not
|
|
||||||
* after each unit of work like with eager flushing.
|
|
||||||
* <p>In case of an existing Session, FLUSH_AUTO will participate in the
|
|
||||||
* existing flush mode, not modifying it for the current operation.
|
|
||||||
* This in particular means that this setting will not modify an existing
|
|
||||||
* flush mode NEVER, in contrast to FLUSH_EAGER.
|
|
||||||
* @see #setFlushMode
|
|
||||||
*/
|
|
||||||
public static final int FLUSH_AUTO = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Eager flushing leads to immediate synchronization with the database,
|
|
||||||
* even if in a transaction. This causes inconsistencies to show up and throw
|
|
||||||
* a respective exception immediately, and JDBC access code that participates
|
|
||||||
* in the same transaction will see the changes as the database is already
|
|
||||||
* aware of them then. But the drawbacks are:
|
|
||||||
* <ul>
|
|
||||||
* <li>additional communication roundtrips with the database, instead of a
|
|
||||||
* single batch at transaction commit;
|
|
||||||
* <li>the fact that an actual database rollback is needed if the Hibernate
|
|
||||||
* transaction rolls back (due to already submitted SQL statements).
|
|
||||||
* </ul>
|
|
||||||
* <p>In case of an existing Session, FLUSH_EAGER will turn the flush mode
|
|
||||||
* to AUTO for the scope of the current operation and issue a flush at the
|
|
||||||
* end, resetting the previous flush mode afterwards.
|
|
||||||
* @see #setFlushMode
|
|
||||||
*/
|
|
||||||
public static final int FLUSH_EAGER = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flushing at commit only is intended for units of work where no
|
|
||||||
* intermediate flushing is desired, not even for find operations
|
|
||||||
* that might involve already modified instances.
|
|
||||||
* <p>In case of an existing Session, FLUSH_COMMIT will turn the flush mode
|
|
||||||
* to COMMIT for the scope of the current operation, resetting the previous
|
|
||||||
* flush mode afterwards. The only exception is an existing flush mode
|
|
||||||
* NEVER, which will not be modified through this setting.
|
|
||||||
* @see #setFlushMode
|
|
||||||
*/
|
|
||||||
public static final int FLUSH_COMMIT = 3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flushing before every query statement is rarely necessary.
|
|
||||||
* It is only available for special needs.
|
|
||||||
* <p>In case of an existing Session, FLUSH_ALWAYS will turn the flush mode
|
|
||||||
* to ALWAYS for the scope of the current operation, resetting the previous
|
|
||||||
* flush mode afterwards.
|
|
||||||
* @see #setFlushMode
|
|
||||||
*/
|
|
||||||
public static final int FLUSH_ALWAYS = 4;
|
|
||||||
|
|
||||||
|
|
||||||
/** Constants instance for HibernateAccessor */
|
|
||||||
private static final Constants constants = new Constants(HibernateAccessor.class);
|
|
||||||
|
|
||||||
/** Logger available to subclasses */
|
|
||||||
protected final Log logger = LogFactory.getLog(getClass());
|
|
||||||
|
|
||||||
private SessionFactory sessionFactory;
|
|
||||||
|
|
||||||
private Object entityInterceptor;
|
|
||||||
|
|
||||||
private SQLExceptionTranslator jdbcExceptionTranslator;
|
|
||||||
|
|
||||||
private SQLExceptionTranslator defaultJdbcExceptionTranslator;
|
|
||||||
|
|
||||||
private int flushMode = FLUSH_AUTO;
|
|
||||||
|
|
||||||
private String[] filterNames;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Just needed for entityInterceptorBeanName.
|
|
||||||
* @see #setEntityInterceptorBeanName
|
|
||||||
*/
|
|
||||||
private BeanFactory beanFactory;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Hibernate SessionFactory that should be used to create
|
|
||||||
* Hibernate Sessions.
|
|
||||||
*/
|
|
||||||
public void setSessionFactory(SessionFactory sessionFactory) {
|
|
||||||
this.sessionFactory = sessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the Hibernate SessionFactory that should be used to create
|
|
||||||
* Hibernate Sessions.
|
|
||||||
*/
|
|
||||||
public SessionFactory getSessionFactory() {
|
|
||||||
return this.sessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the bean name of a Hibernate entity interceptor that allows to inspect
|
|
||||||
* and change property values before writing to and reading from the database.
|
|
||||||
* Will get applied to any new Session created by this transaction manager.
|
|
||||||
* <p>Requires the bean factory to be known, to be able to resolve the bean
|
|
||||||
* name to an interceptor instance on session creation. Typically used for
|
|
||||||
* prototype interceptors, i.e. a new interceptor instance per session.
|
|
||||||
* <p>Can also be used for shared interceptor instances, but it is recommended
|
|
||||||
* to set the interceptor reference directly in such a scenario.
|
|
||||||
* @param entityInterceptorBeanName the name of the entity interceptor in
|
|
||||||
* the bean factory
|
|
||||||
* @see #setBeanFactory
|
|
||||||
* @see #setEntityInterceptor
|
|
||||||
*/
|
|
||||||
public void setEntityInterceptorBeanName(String entityInterceptorBeanName) {
|
|
||||||
this.entityInterceptor = entityInterceptorBeanName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a Hibernate entity interceptor that allows to inspect and change
|
|
||||||
* property values before writing to and reading from the database.
|
|
||||||
* Will get applied to any <b>new</b> Session created by this object.
|
|
||||||
* <p>Such an interceptor can either be set at the SessionFactory level,
|
|
||||||
* i.e. on LocalSessionFactoryBean, or at the Session level, i.e. on
|
|
||||||
* HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager.
|
|
||||||
* It's preferable to set it on LocalSessionFactoryBean or HibernateTransactionManager
|
|
||||||
* to avoid repeated configuration and guarantee consistent behavior in transactions.
|
|
||||||
* @see #setEntityInterceptorBeanName
|
|
||||||
* @see LocalSessionFactoryBean#setEntityInterceptor
|
|
||||||
* @see HibernateTransactionManager#setEntityInterceptor
|
|
||||||
*/
|
|
||||||
public void setEntityInterceptor(Interceptor entityInterceptor) {
|
|
||||||
this.entityInterceptor = entityInterceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the current Hibernate entity interceptor, or {@code null} if none.
|
|
||||||
* Resolves an entity interceptor bean name via the bean factory,
|
|
||||||
* if necessary.
|
|
||||||
* @throws IllegalStateException if bean name specified but no bean factory set
|
|
||||||
* @throws org.springframework.beans.BeansException if bean name resolution via the bean factory failed
|
|
||||||
* @see #setEntityInterceptor
|
|
||||||
* @see #setEntityInterceptorBeanName
|
|
||||||
* @see #setBeanFactory
|
|
||||||
*/
|
|
||||||
public Interceptor getEntityInterceptor() throws IllegalStateException, BeansException {
|
|
||||||
if (this.entityInterceptor instanceof String) {
|
|
||||||
if (this.beanFactory == null) {
|
|
||||||
throw new IllegalStateException("Cannot get entity interceptor via bean name if no bean factory set");
|
|
||||||
}
|
|
||||||
return this.beanFactory.getBean((String) this.entityInterceptor, Interceptor.class);
|
|
||||||
}
|
|
||||||
return (Interceptor) this.entityInterceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the JDBC exception translator for this instance.
|
|
||||||
* <p>Applied to any SQLException root cause of a Hibernate JDBCException,
|
|
||||||
* overriding Hibernate's default SQLException translation (which is
|
|
||||||
* based on Hibernate's Dialect for a specific target database).
|
|
||||||
* @param jdbcExceptionTranslator the exception translator
|
|
||||||
* @see java.sql.SQLException
|
|
||||||
* @see org.hibernate.JDBCException
|
|
||||||
* @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
|
|
||||||
* @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
|
|
||||||
*/
|
|
||||||
public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
|
|
||||||
this.jdbcExceptionTranslator = jdbcExceptionTranslator;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the JDBC exception translator for this instance, if any.
|
|
||||||
*/
|
|
||||||
public SQLExceptionTranslator getJdbcExceptionTranslator() {
|
|
||||||
return this.jdbcExceptionTranslator;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the flush behavior by the name of the respective constant
|
|
||||||
* in this class, e.g. "FLUSH_AUTO". Default is "FLUSH_AUTO".
|
|
||||||
* @param constantName name of the constant
|
|
||||||
* @see #setFlushMode
|
|
||||||
* @see #FLUSH_AUTO
|
|
||||||
*/
|
|
||||||
public void setFlushModeName(String constantName) {
|
|
||||||
setFlushMode(constants.asNumber(constantName).intValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the flush behavior to one of the constants in this class.
|
|
||||||
* Default is FLUSH_AUTO.
|
|
||||||
* @see #setFlushModeName
|
|
||||||
* @see #FLUSH_AUTO
|
|
||||||
*/
|
|
||||||
public void setFlushMode(int flushMode) {
|
|
||||||
this.flushMode = flushMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return if a flush should be forced after executing the callback code.
|
|
||||||
*/
|
|
||||||
public int getFlushMode() {
|
|
||||||
return this.flushMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the name of a Hibernate filter to be activated for all
|
|
||||||
* Sessions that this accessor works with.
|
|
||||||
* <p>This filter will be enabled at the beginning of each operation
|
|
||||||
* and correspondingly disabled at the end of the operation.
|
|
||||||
* This will work for newly opened Sessions as well as for existing
|
|
||||||
* Sessions (for example, within a transaction).
|
|
||||||
* @see #enableFilters(org.hibernate.Session)
|
|
||||||
* @see org.hibernate.Session#enableFilter(String)
|
|
||||||
* @see LocalSessionFactoryBean#setFilterDefinitions
|
|
||||||
*/
|
|
||||||
public void setFilterName(String filter) {
|
|
||||||
this.filterNames = new String[] {filter};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set one or more names of Hibernate filters to be activated for all
|
|
||||||
* Sessions that this accessor works with.
|
|
||||||
* <p>Each of those filters will be enabled at the beginning of each
|
|
||||||
* operation and correspondingly disabled at the end of the operation.
|
|
||||||
* This will work for newly opened Sessions as well as for existing
|
|
||||||
* Sessions (for example, within a transaction).
|
|
||||||
* @see #enableFilters(org.hibernate.Session)
|
|
||||||
* @see org.hibernate.Session#enableFilter(String)
|
|
||||||
* @see LocalSessionFactoryBean#setFilterDefinitions
|
|
||||||
*/
|
|
||||||
public void setFilterNames(String... filterNames) {
|
|
||||||
this.filterNames = filterNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the names of Hibernate filters to be activated, if any.
|
|
||||||
*/
|
|
||||||
public String[] getFilterNames() {
|
|
||||||
return this.filterNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The bean factory just needs to be known for resolving entity interceptor
|
|
||||||
* bean names. It does not need to be set for any other mode of operation.
|
|
||||||
* @see #setEntityInterceptorBeanName
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void setBeanFactory(BeanFactory beanFactory) {
|
|
||||||
this.beanFactory = beanFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterPropertiesSet() {
|
|
||||||
if (getSessionFactory() == null) {
|
|
||||||
throw new IllegalArgumentException("Property 'sessionFactory' is required");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply the flush mode that's been specified for this accessor
|
|
||||||
* to the given Session.
|
|
||||||
* @param session the current Hibernate Session
|
|
||||||
* @param existingTransaction if executing within an existing transaction
|
|
||||||
* @return the previous flush mode to restore after the operation,
|
|
||||||
* or {@code null} if none
|
|
||||||
* @see #setFlushMode
|
|
||||||
* @see org.hibernate.Session#setFlushMode
|
|
||||||
*/
|
|
||||||
protected FlushMode applyFlushMode(Session session, boolean existingTransaction) {
|
|
||||||
if (getFlushMode() == FLUSH_NEVER) {
|
|
||||||
if (existingTransaction) {
|
|
||||||
FlushMode previousFlushMode = session.getFlushMode();
|
|
||||||
if (!previousFlushMode.lessThan(FlushMode.COMMIT)) {
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
|
||||||
return previousFlushMode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (getFlushMode() == FLUSH_EAGER) {
|
|
||||||
if (existingTransaction) {
|
|
||||||
FlushMode previousFlushMode = session.getFlushMode();
|
|
||||||
if (!previousFlushMode.equals(FlushMode.AUTO)) {
|
|
||||||
session.setFlushMode(FlushMode.AUTO);
|
|
||||||
return previousFlushMode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// rely on default FlushMode.AUTO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (getFlushMode() == FLUSH_COMMIT) {
|
|
||||||
if (existingTransaction) {
|
|
||||||
FlushMode previousFlushMode = session.getFlushMode();
|
|
||||||
if (previousFlushMode.equals(FlushMode.AUTO) || previousFlushMode.equals(FlushMode.ALWAYS)) {
|
|
||||||
session.setFlushMode(FlushMode.COMMIT);
|
|
||||||
return previousFlushMode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
session.setFlushMode(FlushMode.COMMIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (getFlushMode() == FLUSH_ALWAYS) {
|
|
||||||
if (existingTransaction) {
|
|
||||||
FlushMode previousFlushMode = session.getFlushMode();
|
|
||||||
if (!previousFlushMode.equals(FlushMode.ALWAYS)) {
|
|
||||||
session.setFlushMode(FlushMode.ALWAYS);
|
|
||||||
return previousFlushMode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
session.setFlushMode(FlushMode.ALWAYS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flush the given Hibernate Session if necessary.
|
|
||||||
* @param session the current Hibernate Session
|
|
||||||
* @param existingTransaction if executing within an existing transaction
|
|
||||||
* @throws HibernateException in case of Hibernate flushing errors
|
|
||||||
*/
|
|
||||||
protected void flushIfNecessary(Session session, boolean existingTransaction) throws HibernateException {
|
|
||||||
if (getFlushMode() == FLUSH_EAGER || (!existingTransaction && getFlushMode() != FLUSH_NEVER)) {
|
|
||||||
logger.debug("Eagerly flushing Hibernate session");
|
|
||||||
session.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the given HibernateException to an appropriate exception
|
|
||||||
* from the {@code org.springframework.dao} hierarchy.
|
|
||||||
* <p>Will automatically apply a specified SQLExceptionTranslator to a
|
|
||||||
* Hibernate JDBCException, else rely on Hibernate's default translation.
|
|
||||||
* @param ex HibernateException that occured
|
|
||||||
* @return a corresponding DataAccessException
|
|
||||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
|
||||||
* @see #setJdbcExceptionTranslator
|
|
||||||
*/
|
|
||||||
public DataAccessException convertHibernateAccessException(HibernateException ex) {
|
|
||||||
if (getJdbcExceptionTranslator() != null && ex instanceof JDBCException) {
|
|
||||||
return convertJdbcAccessException((JDBCException) ex, getJdbcExceptionTranslator());
|
|
||||||
}
|
|
||||||
else if (GenericJDBCException.class == ex.getClass()) {
|
|
||||||
return convertJdbcAccessException((GenericJDBCException) ex, getDefaultJdbcExceptionTranslator());
|
|
||||||
}
|
|
||||||
return SessionFactoryUtils.convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the given Hibernate JDBCException to an appropriate exception
|
|
||||||
* from the {@code org.springframework.dao} hierarchy, using the
|
|
||||||
* given SQLExceptionTranslator.
|
|
||||||
* @param ex Hibernate JDBCException that occured
|
|
||||||
* @param translator the SQLExceptionTranslator to use
|
|
||||||
* @return a corresponding DataAccessException
|
|
||||||
*/
|
|
||||||
protected DataAccessException convertJdbcAccessException(JDBCException ex, SQLExceptionTranslator translator) {
|
|
||||||
return translator.translate("Hibernate operation: " + ex.getMessage(), ex.getSQL(), ex.getSQLException());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the given SQLException to an appropriate exception from the
|
|
||||||
* {@code org.springframework.dao} hierarchy. Can be overridden in subclasses.
|
|
||||||
* <p>Note that a direct SQLException can just occur when callback code
|
|
||||||
* performs direct JDBC access via {@code Session.connection()}.
|
|
||||||
* @param ex the SQLException
|
|
||||||
* @return the corresponding DataAccessException instance
|
|
||||||
* @see #setJdbcExceptionTranslator
|
|
||||||
*/
|
|
||||||
protected DataAccessException convertJdbcAccessException(SQLException ex) {
|
|
||||||
SQLExceptionTranslator translator = getJdbcExceptionTranslator();
|
|
||||||
if (translator == null) {
|
|
||||||
translator = getDefaultJdbcExceptionTranslator();
|
|
||||||
}
|
|
||||||
return translator.translate("Hibernate-related JDBC operation", null, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain a default SQLExceptionTranslator, lazily creating it if necessary.
|
|
||||||
* <p>Creates a default
|
|
||||||
* {@link org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator}
|
|
||||||
* for the SessionFactory's underlying DataSource.
|
|
||||||
*/
|
|
||||||
protected synchronized SQLExceptionTranslator getDefaultJdbcExceptionTranslator() {
|
|
||||||
if (this.defaultJdbcExceptionTranslator == null) {
|
|
||||||
this.defaultJdbcExceptionTranslator = SessionFactoryUtils.newJdbcExceptionTranslator(getSessionFactory());
|
|
||||||
}
|
|
||||||
return this.defaultJdbcExceptionTranslator;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable the specified filters on the given Session.
|
|
||||||
* @param session the current Hibernate Session
|
|
||||||
* @see #setFilterNames
|
|
||||||
* @see org.hibernate.Session#enableFilter(String)
|
|
||||||
*/
|
|
||||||
protected void enableFilters(Session session) {
|
|
||||||
String[] filterNames = getFilterNames();
|
|
||||||
if (filterNames != null) {
|
|
||||||
for (String filterName : filterNames) {
|
|
||||||
session.enableFilter(filterName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disable the specified filters on the given Session.
|
|
||||||
* @param session the current Hibernate Session
|
|
||||||
* @see #setFilterNames
|
|
||||||
* @see org.hibernate.Session#disableFilter(String)
|
|
||||||
*/
|
|
||||||
protected void disableFilters(Session session) {
|
|
||||||
String[] filterNames = getFilterNames();
|
|
||||||
if (filterNames != null) {
|
|
||||||
for (String filterName : filterNames) {
|
|
||||||
session.disableFilter(filterName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2016 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback interface for Hibernate code. To be used with {@link HibernateTemplate}'s
|
|
||||||
* execution methods, often as anonymous classes within a method implementation.
|
|
||||||
* A typical implementation will call {@code Session.load/find/update} to perform
|
|
||||||
* some operations on persistent objects. It can also perform direct JDBC operations
|
|
||||||
* via Hibernate's {@code Session.connection()}, operating on a JDBC Connection.
|
|
||||||
*
|
|
||||||
* <p>Note that Hibernate works on unmodified plain Java objects, performing dirty
|
|
||||||
* detection via copies made at load time. Returned objects can thus be used outside
|
|
||||||
* of an active Hibernate Session without any hassle, e.g. for display in a web GUI.
|
|
||||||
* Reassociating such instances with a new Session, e.g. for updates when coming
|
|
||||||
* back from the GUI, is straightforward, as the instance has kept its identity.
|
|
||||||
* You should care to reassociate them as early as possible though, to avoid having
|
|
||||||
* already loaded a version from the database in the same Session.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see HibernateTemplate
|
|
||||||
* @see HibernateTransactionManager
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public interface HibernateCallback<T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets called by {@code HibernateTemplate.execute} with an active
|
|
||||||
* Hibernate {@code Session}. Does not need to care about activating
|
|
||||||
* or closing the {@code Session}, or handling transactions.
|
|
||||||
* <p>If called without a thread-bound Hibernate transaction (initiated
|
|
||||||
* by HibernateTransactionManager), the code will simply get executed on the
|
|
||||||
* underlying JDBC connection with its transactional semantics. If Hibernate
|
|
||||||
* is configured to use a JTA-aware DataSource, the JDBC connection and thus
|
|
||||||
* the callback code will be transactional if a JTA transaction is active.
|
|
||||||
* <p>Allows for returning a result object created within the callback,
|
|
||||||
* i.e. a domain object or a collection of domain objects.
|
|
||||||
* A thrown custom RuntimeException is treated as an application exception:
|
|
||||||
* It gets propagated to the caller of the template.
|
|
||||||
* @param session active Hibernate session
|
|
||||||
* @return a result object, or {@code null} if none
|
|
||||||
* @throws HibernateException if thrown by the Hibernate API
|
|
||||||
* @throws SQLException if thrown by Hibernate-exposed JDBC API
|
|
||||||
* @see HibernateTemplate#execute
|
|
||||||
* @see HibernateTemplate#executeFind
|
|
||||||
*/
|
|
||||||
T doInHibernate(Session session) throws HibernateException, SQLException;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.JDBCException;
|
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException;
|
|
||||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
|
||||||
import org.springframework.jdbc.support.SQLExceptionTranslator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link PersistenceExceptionTranslator} capable of translating {@link HibernateException}
|
|
||||||
* instances to Spring's {@link DataAccessException} hierarchy.
|
|
||||||
*
|
|
||||||
* <p>Extended by {@link LocalSessionFactoryBean}, so there is no need to declare this
|
|
||||||
* translator in addition to a {@code LocalSessionFactoryBean}.
|
|
||||||
*
|
|
||||||
* <p>When configuring the container with {@code @Configuration} classes, a {@code @Bean}
|
|
||||||
* of this type must be registered manually.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @author Chris Beams
|
|
||||||
* @since 3.1
|
|
||||||
* @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
|
|
||||||
* @see SessionFactoryUtils#convertHibernateAccessException(HibernateException)
|
|
||||||
* @see SQLExceptionTranslator
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class HibernateExceptionTranslator implements PersistenceExceptionTranslator {
|
|
||||||
|
|
||||||
private SQLExceptionTranslator jdbcExceptionTranslator;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the JDBC exception translator for the SessionFactory,
|
|
||||||
* exposed via the PersistenceExceptionTranslator interface.
|
|
||||||
* <p>Applied to any SQLException root cause of a Hibernate JDBCException,
|
|
||||||
* overriding Hibernate's default SQLException translation (which is
|
|
||||||
* based on Hibernate's Dialect for a specific target database).
|
|
||||||
* @param jdbcExceptionTranslator the exception translator
|
|
||||||
* @see java.sql.SQLException
|
|
||||||
* @see org.hibernate.JDBCException
|
|
||||||
* @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
|
|
||||||
* @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
|
|
||||||
* @see org.springframework.dao.support.PersistenceExceptionTranslator
|
|
||||||
*/
|
|
||||||
public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
|
|
||||||
this.jdbcExceptionTranslator = jdbcExceptionTranslator;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
|
|
||||||
if (ex instanceof HibernateException) {
|
|
||||||
return convertHibernateAccessException((HibernateException) ex);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the given HibernateException to an appropriate exception from the
|
|
||||||
* {@code org.springframework.dao} hierarchy.
|
|
||||||
* <p>Will automatically apply a specified SQLExceptionTranslator to a
|
|
||||||
* Hibernate JDBCException, else rely on Hibernate's default translation.
|
|
||||||
* @param ex HibernateException that occured
|
|
||||||
* @return a corresponding DataAccessException
|
|
||||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
|
||||||
* @see #setJdbcExceptionTranslator
|
|
||||||
*/
|
|
||||||
protected DataAccessException convertHibernateAccessException(HibernateException ex) {
|
|
||||||
if (this.jdbcExceptionTranslator != null && ex instanceof JDBCException) {
|
|
||||||
JDBCException jdbcEx = (JDBCException) ex;
|
|
||||||
return this.jdbcExceptionTranslator.translate(
|
|
||||||
"Hibernate operation: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException());
|
|
||||||
}
|
|
||||||
return SessionFactoryUtils.convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,157 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import org.aopalliance.intercept.MethodInterceptor;
|
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
|
||||||
import org.hibernate.FlushMode;
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This interceptor binds a new Hibernate Session to the thread before a method
|
|
||||||
* call, closing and removing it afterwards in case of any method outcome.
|
|
||||||
* If there already is a pre-bound Session (e.g. from HibernateTransactionManager,
|
|
||||||
* or from a surrounding Hibernate-intercepted method), the interceptor simply
|
|
||||||
* participates in it.
|
|
||||||
*
|
|
||||||
* <p>Application code must retrieve a Hibernate Session via the
|
|
||||||
* {@code SessionFactoryUtils.getSession} method or - preferably -
|
|
||||||
* Hibernate's own {@code SessionFactory.getCurrentSession()} method, to be
|
|
||||||
* able to detect a thread-bound Session. Typically, the code will look like as follows:
|
|
||||||
*
|
|
||||||
* <pre class="code">
|
|
||||||
* public void doSomeDataAccessAction() {
|
|
||||||
* Session session = this.sessionFactory.getCurrentSession();
|
|
||||||
* ...
|
|
||||||
* // No need to close the Session or translate exceptions!
|
|
||||||
* }</pre>
|
|
||||||
*
|
|
||||||
* Note that this interceptor automatically translates HibernateExceptions,
|
|
||||||
* via delegating to the {@code SessionFactoryUtils.convertHibernateAccessException}
|
|
||||||
* method that converts them to exceptions that are compatible with the
|
|
||||||
* {@code org.springframework.dao} exception hierarchy (like HibernateTemplate does).
|
|
||||||
* This can be turned off if the raw exceptions are preferred.
|
|
||||||
*
|
|
||||||
* <p>This class can be considered a declarative alternative to HibernateTemplate's
|
|
||||||
* callback approach. The advantages are:
|
|
||||||
* <ul>
|
|
||||||
* <li>no anonymous classes necessary for callback implementations;
|
|
||||||
* <li>the possibility to throw any application exceptions from within data access code.
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* <p>The drawback is the dependency on interceptor configuration. However, note
|
|
||||||
* that this interceptor is usually <i>not</i> necessary in scenarios where the
|
|
||||||
* data access code always executes within transactions. A transaction will always
|
|
||||||
* have a thread-bound Session in the first place, so adding this interceptor to the
|
|
||||||
* configuration just adds value when fine-tuning Session settings like the flush mode
|
|
||||||
* - or when relying on exception translation.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
|
||||||
* @see HibernateTransactionManager
|
|
||||||
* @see HibernateTemplate
|
|
||||||
* @deprecated as of Spring 3.2.7, in favor of either HibernateTemplate usage or
|
|
||||||
* native Hibernate API usage within transactions, in combination with a general
|
|
||||||
* {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor}.
|
|
||||||
* Note: This class does not have an equivalent replacement in {@code orm.hibernate4}.
|
|
||||||
* If you desperately need a scoped Session bound through AOP, consider the newly
|
|
||||||
* introduced {@link org.springframework.orm.hibernate3.support.OpenSessionInterceptor}.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class HibernateInterceptor extends HibernateAccessor implements MethodInterceptor {
|
|
||||||
|
|
||||||
private boolean exceptionConversionEnabled = true;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether to convert any HibernateException raised to a Spring DataAccessException,
|
|
||||||
* compatible with the {@code org.springframework.dao} exception hierarchy.
|
|
||||||
* <p>Default is "true". Turn this flag off to let the caller receive raw exceptions
|
|
||||||
* as-is, without any wrapping.
|
|
||||||
* @see org.springframework.dao.DataAccessException
|
|
||||||
*/
|
|
||||||
public void setExceptionConversionEnabled(boolean exceptionConversionEnabled) {
|
|
||||||
this.exceptionConversionEnabled = exceptionConversionEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
|
|
||||||
Session session = getSession();
|
|
||||||
SessionHolder sessionHolder =
|
|
||||||
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
|
|
||||||
|
|
||||||
boolean existingTransaction = (sessionHolder != null && sessionHolder.containsSession(session));
|
|
||||||
if (existingTransaction) {
|
|
||||||
logger.debug("Found thread-bound Session for HibernateInterceptor");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (sessionHolder != null) {
|
|
||||||
sessionHolder.addSession(session);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), new SessionHolder(session));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FlushMode previousFlushMode = null;
|
|
||||||
try {
|
|
||||||
previousFlushMode = applyFlushMode(session, existingTransaction);
|
|
||||||
enableFilters(session);
|
|
||||||
Object retVal = methodInvocation.proceed();
|
|
||||||
flushIfNecessary(session, existingTransaction);
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
if (this.exceptionConversionEnabled) {
|
|
||||||
throw convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if (existingTransaction) {
|
|
||||||
logger.debug("Not closing pre-bound Hibernate Session after HibernateInterceptor");
|
|
||||||
disableFilters(session);
|
|
||||||
if (previousFlushMode != null) {
|
|
||||||
session.setFlushMode(previousFlushMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
|
|
||||||
if (sessionHolder == null || sessionHolder.doesNotHoldNonDefaultSession()) {
|
|
||||||
TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a Session for use by this interceptor.
|
|
||||||
* @see SessionFactoryUtils#getSession
|
|
||||||
*/
|
|
||||||
protected Session getSession() {
|
|
||||||
return SessionFactoryUtils.getSession(
|
|
||||||
getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
import org.hibernate.JDBCException;
|
|
||||||
|
|
||||||
import org.springframework.dao.UncategorizedDataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate-specific subclass of UncategorizedDataAccessException,
|
|
||||||
* for JDBC exceptions that Hibernate wrapped.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class HibernateJdbcException extends UncategorizedDataAccessException {
|
|
||||||
|
|
||||||
public HibernateJdbcException(JDBCException ex) {
|
|
||||||
super("JDBC exception on Hibernate data access: SQLException for SQL [" + ex.getSQL() + "]; SQL state [" +
|
|
||||||
ex.getSQLState() + "]; error code [" + ex.getErrorCode() + "]; " + ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the underlying SQLException.
|
|
||||||
*/
|
|
||||||
public SQLException getSQLException() {
|
|
||||||
return ((JDBCException) getCause()).getSQLException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the SQL that led to the problem.
|
|
||||||
*/
|
|
||||||
public String getSql() {
|
|
||||||
return ((JDBCException) getCause()).getSQL();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import org.hibernate.UnresolvableObjectException;
|
|
||||||
import org.hibernate.WrongClassException;
|
|
||||||
|
|
||||||
import org.springframework.orm.ObjectRetrievalFailureException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate-specific subclass of ObjectRetrievalFailureException.
|
|
||||||
* Converts Hibernate's UnresolvableObjectException and WrongClassException.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class HibernateObjectRetrievalFailureException extends ObjectRetrievalFailureException {
|
|
||||||
|
|
||||||
public HibernateObjectRetrievalFailureException(UnresolvableObjectException ex) {
|
|
||||||
super(ex.getEntityName(), ex.getIdentifier(), ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HibernateObjectRetrievalFailureException(WrongClassException ex) {
|
|
||||||
super(ex.getEntityName(), ex.getIdentifier(), ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,921 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.hibernate.Filter;
|
|
||||||
import org.hibernate.LockMode;
|
|
||||||
import org.hibernate.ReplicationMode;
|
|
||||||
import org.hibernate.criterion.DetachedCriteria;
|
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface that specifies a basic set of Hibernate operations,
|
|
||||||
* implemented by {@link HibernateTemplate}. Not often used, but a useful
|
|
||||||
* option to enhance testability, as it can easily be mocked or stubbed.
|
|
||||||
*
|
|
||||||
* <p>Defines {@code HibernateTemplate}'s data access methods that
|
|
||||||
* mirror various {@link org.hibernate.Session} methods. Users are
|
|
||||||
* strongly encouraged to read the Hibernate {@code Session} javadocs
|
|
||||||
* for details on the semantics of those methods.
|
|
||||||
*
|
|
||||||
* <p>Note that operations that return an {@link java.util.Iterator} (i.e.
|
|
||||||
* {@code iterate(..)}) are supposed to be used within Spring-driven
|
|
||||||
* or JTA-driven transactions (with {@link HibernateTransactionManager},
|
|
||||||
* {@link org.springframework.transaction.jta.JtaTransactionManager},
|
|
||||||
* or EJB CMT). Else, the {@code Iterator} won't be able to read
|
|
||||||
* results from its {@link java.sql.ResultSet} anymore, as the underlying
|
|
||||||
* Hibernate {@code Session} will already have been closed.
|
|
||||||
*
|
|
||||||
* <p>Note that lazy loading will just work with an open Hibernate
|
|
||||||
* {@code Session}, either within a transaction or within
|
|
||||||
* {@link org.springframework.orm.hibernate3.support.OpenSessionInViewFilter}/
|
|
||||||
* {@link org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor}.
|
|
||||||
* Furthermore, some operations just make sense within transactions,
|
|
||||||
* for example: {@code contains}, {@code evict}, {@code lock},
|
|
||||||
* {@code flush}, {@code clear}.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see HibernateTemplate
|
|
||||||
* @see org.hibernate.Session
|
|
||||||
* @see HibernateTransactionManager
|
|
||||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
|
||||||
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
|
|
||||||
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public interface HibernateOperations {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the action specified by the given action object within a
|
|
||||||
* {@link org.hibernate.Session}.
|
|
||||||
* <p>Application exceptions thrown by the action object get propagated
|
|
||||||
* to the caller (can only be unchecked). Hibernate exceptions are
|
|
||||||
* transformed into appropriate DAO ones. Allows for returning a result
|
|
||||||
* object, that is a domain object or a collection of domain objects.
|
|
||||||
* <p>Note: Callback code is not supposed to handle transactions itself!
|
|
||||||
* Use an appropriate transaction manager like
|
|
||||||
* {@link HibernateTransactionManager}. Generally, callback code must not
|
|
||||||
* touch any {@code Session} lifecycle methods, like close,
|
|
||||||
* disconnect, or reconnect, to let the template do its work.
|
|
||||||
* @param action callback object that specifies the Hibernate action
|
|
||||||
* @return a result object returned by the action, or {@code null}
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see HibernateTransactionManager
|
|
||||||
* @see org.hibernate.Session
|
|
||||||
*/
|
|
||||||
<T> T execute(HibernateCallback<T> action) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the specified action assuming that the result object is a
|
|
||||||
* {@link List}.
|
|
||||||
* <p>This is a convenience method for executing Hibernate find calls or
|
|
||||||
* queries within an action.
|
|
||||||
* @param action callback object that specifies the Hibernate action
|
|
||||||
* @return a List result returned by the action, or {@code null}
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @deprecated as of Spring 3.2.7, in favor of using a regular {@link #execute}
|
|
||||||
* call with a generic List type declared
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
List<?> executeFind(HibernateCallback<?> action) throws DataAccessException;
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
// Convenience methods for loading individual objects
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the persistent instance of the given entity class
|
|
||||||
* with the given identifier, or {@code null} if not found.
|
|
||||||
* <p>This method is a thin wrapper around
|
|
||||||
* {@link org.hibernate.Session#get(Class, java.io.Serializable)} for convenience.
|
|
||||||
* For an explanation of the exact semantics of this method, please do refer to
|
|
||||||
* the Hibernate API documentation in the first instance.
|
|
||||||
* @param entityClass a persistent class
|
|
||||||
* @param id the identifier of the persistent instance
|
|
||||||
* @return the persistent instance, or {@code null} if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#get(Class, java.io.Serializable)
|
|
||||||
*/
|
|
||||||
<T> T get(Class<T> entityClass, Serializable id) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the persistent instance of the given entity class
|
|
||||||
* with the given identifier, or {@code null} if not found.
|
|
||||||
* <p>Obtains the specified lock mode if the instance exists.
|
|
||||||
* <p>This method is a thin wrapper around
|
|
||||||
* {@link org.hibernate.Session#get(Class, java.io.Serializable, LockMode)} for convenience.
|
|
||||||
* For an explanation of the exact semantics of this method, please do refer to
|
|
||||||
* the Hibernate API documentation in the first instance.
|
|
||||||
* @param entityClass a persistent class
|
|
||||||
* @param id the identifier of the persistent instance
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @return the persistent instance, or {@code null} if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#get(Class, java.io.Serializable, org.hibernate.LockMode)
|
|
||||||
*/
|
|
||||||
<T> T get(Class<T> entityClass, Serializable id, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the persistent instance of the given entity class
|
|
||||||
* with the given identifier, or {@code null} if not found.
|
|
||||||
* <p>This method is a thin wrapper around
|
|
||||||
* {@link org.hibernate.Session#get(String, java.io.Serializable)} for convenience.
|
|
||||||
* For an explanation of the exact semantics of this method, please do refer to
|
|
||||||
* the Hibernate API documentation in the first instance.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param id the identifier of the persistent instance
|
|
||||||
* @return the persistent instance, or {@code null} if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#get(Class, java.io.Serializable)
|
|
||||||
*/
|
|
||||||
Object get(String entityName, Serializable id) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the persistent instance of the given entity class
|
|
||||||
* with the given identifier, or {@code null} if not found.
|
|
||||||
* Obtains the specified lock mode if the instance exists.
|
|
||||||
* <p>This method is a thin wrapper around
|
|
||||||
* {@link org.hibernate.Session#get(String, java.io.Serializable, LockMode)} for convenience.
|
|
||||||
* For an explanation of the exact semantics of this method, please do refer to
|
|
||||||
* the Hibernate API documentation in the first instance.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param id the identifier of the persistent instance
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @return the persistent instance, or {@code null} if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#get(Class, java.io.Serializable, org.hibernate.LockMode)
|
|
||||||
*/
|
|
||||||
Object get(String entityName, Serializable id, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the persistent instance of the given entity class
|
|
||||||
* with the given identifier, throwing an exception if not found.
|
|
||||||
* <p>This method is a thin wrapper around
|
|
||||||
* {@link org.hibernate.Session#load(Class, java.io.Serializable)} for convenience.
|
|
||||||
* For an explanation of the exact semantics of this method, please do refer to
|
|
||||||
* the Hibernate API documentation in the first instance.
|
|
||||||
* @param entityClass a persistent class
|
|
||||||
* @param id the identifier of the persistent instance
|
|
||||||
* @return the persistent instance
|
|
||||||
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#load(Class, java.io.Serializable)
|
|
||||||
*/
|
|
||||||
<T> T load(Class<T> entityClass, Serializable id) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the persistent instance of the given entity class
|
|
||||||
* with the given identifier, throwing an exception if not found.
|
|
||||||
* Obtains the specified lock mode if the instance exists.
|
|
||||||
* <p>This method is a thin wrapper around
|
|
||||||
* {@link org.hibernate.Session#load(Class, java.io.Serializable, LockMode)} for convenience.
|
|
||||||
* For an explanation of the exact semantics of this method, please do refer to
|
|
||||||
* the Hibernate API documentation in the first instance.
|
|
||||||
* @param entityClass a persistent class
|
|
||||||
* @param id the identifier of the persistent instance
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @return the persistent instance
|
|
||||||
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#load(Class, java.io.Serializable)
|
|
||||||
*/
|
|
||||||
<T> T load(Class<T> entityClass, Serializable id, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the persistent instance of the given entity class
|
|
||||||
* with the given identifier, throwing an exception if not found.
|
|
||||||
* <p>This method is a thin wrapper around
|
|
||||||
* {@link org.hibernate.Session#load(String, java.io.Serializable)} for convenience.
|
|
||||||
* For an explanation of the exact semantics of this method, please do refer to
|
|
||||||
* the Hibernate API documentation in the first instance.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param id the identifier of the persistent instance
|
|
||||||
* @return the persistent instance
|
|
||||||
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#load(Class, java.io.Serializable)
|
|
||||||
*/
|
|
||||||
Object load(String entityName, Serializable id) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the persistent instance of the given entity class
|
|
||||||
* with the given identifier, throwing an exception if not found.
|
|
||||||
* <p>Obtains the specified lock mode if the instance exists.
|
|
||||||
* <p>This method is a thin wrapper around
|
|
||||||
* {@link org.hibernate.Session#load(String, java.io.Serializable, LockMode)} for convenience.
|
|
||||||
* For an explanation of the exact semantics of this method, please do refer to
|
|
||||||
* the Hibernate API documentation in the first instance.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param id the identifier of the persistent instance
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @return the persistent instance
|
|
||||||
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#load(Class, java.io.Serializable)
|
|
||||||
*/
|
|
||||||
Object load(String entityName, Serializable id, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return all persistent instances of the given entity class.
|
|
||||||
* Note: Use queries or criteria for retrieving a specific subset.
|
|
||||||
* @param entityClass a persistent class
|
|
||||||
* @return a {@link List} containing 0 or more persistent instances
|
|
||||||
* @throws org.springframework.dao.DataAccessException if there is a Hibernate error
|
|
||||||
* @see org.hibernate.Session#createCriteria
|
|
||||||
*/
|
|
||||||
<T> List<T> loadAll(Class<T> entityClass) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the persistent instance with the given identifier
|
|
||||||
* into the given object, throwing an exception if not found.
|
|
||||||
* <p>This method is a thin wrapper around
|
|
||||||
* {@link org.hibernate.Session#load(Object, java.io.Serializable)} for convenience.
|
|
||||||
* For an explanation of the exact semantics of this method, please do refer to
|
|
||||||
* the Hibernate API documentation in the first instance.
|
|
||||||
* @param entity the object (of the target class) to load into
|
|
||||||
* @param id the identifier of the persistent instance
|
|
||||||
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#load(Object, java.io.Serializable)
|
|
||||||
*/
|
|
||||||
void load(Object entity, Serializable id) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Re-read the state of the given persistent instance.
|
|
||||||
* @param entity the persistent instance to re-read
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#refresh(Object)
|
|
||||||
*/
|
|
||||||
void refresh(Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Re-read the state of the given persistent instance.
|
|
||||||
* Obtains the specified lock mode for the instance.
|
|
||||||
* @param entity the persistent instance to re-read
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#refresh(Object, org.hibernate.LockMode)
|
|
||||||
*/
|
|
||||||
void refresh(Object entity, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether the given object is in the Session cache.
|
|
||||||
* @param entity the persistence instance to check
|
|
||||||
* @return whether the given object is in the Session cache
|
|
||||||
* @throws org.springframework.dao.DataAccessException if there is a Hibernate error
|
|
||||||
* @see org.hibernate.Session#contains
|
|
||||||
*/
|
|
||||||
boolean contains(Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the given object from the {@link org.hibernate.Session} cache.
|
|
||||||
* @param entity the persistent instance to evict
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#evict
|
|
||||||
*/
|
|
||||||
void evict(Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Force initialization of a Hibernate proxy or persistent collection.
|
|
||||||
* @param proxy a proxy for a persistent object or a persistent collection
|
|
||||||
* @throws DataAccessException if we can't initialize the proxy, for example
|
|
||||||
* because it is not associated with an active Session
|
|
||||||
* @see org.hibernate.Hibernate#initialize
|
|
||||||
*/
|
|
||||||
void initialize(Object proxy) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an enabled Hibernate {@link Filter} for the given filter name.
|
|
||||||
* The returned {@code Filter} instance can be used to set filter parameters.
|
|
||||||
* @param filterName the name of the filter
|
|
||||||
* @return the enabled Hibernate {@code Filter} (either already
|
|
||||||
* enabled or enabled on the fly by this operation)
|
|
||||||
* @throws IllegalStateException if we are not running within a
|
|
||||||
* transactional Session (in which case this operation does not make sense)
|
|
||||||
*/
|
|
||||||
Filter enableFilter(String filterName) throws IllegalStateException;
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
// Convenience methods for storing individual objects
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the specified lock level upon the given object, implicitly
|
|
||||||
* checking whether the corresponding database entry still exists.
|
|
||||||
* @param entity the persistent instance to lock
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#lock(Object, org.hibernate.LockMode)
|
|
||||||
*/
|
|
||||||
void lock(Object entity, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the specified lock level upon the given object, implicitly
|
|
||||||
* checking whether the corresponding database entry still exists.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the persistent instance to lock
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#lock(String, Object, org.hibernate.LockMode)
|
|
||||||
*/
|
|
||||||
void lock(String entityName, Object entity, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persist the given transient instance.
|
|
||||||
* @param entity the transient instance to persist
|
|
||||||
* @return the generated identifier
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#save(Object)
|
|
||||||
*/
|
|
||||||
Serializable save(Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persist the given transient instance.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the transient instance to persist
|
|
||||||
* @return the generated identifier
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#save(String, Object)
|
|
||||||
*/
|
|
||||||
Serializable save(String entityName, Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the given persistent instance,
|
|
||||||
* associating it with the current Hibernate {@link org.hibernate.Session}.
|
|
||||||
* @param entity the persistent instance to update
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#update(Object)
|
|
||||||
*/
|
|
||||||
void update(Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the given persistent instance,
|
|
||||||
* associating it with the current Hibernate {@link org.hibernate.Session}.
|
|
||||||
* <p>Obtains the specified lock mode if the instance exists, implicitly
|
|
||||||
* checking whether the corresponding database entry still exists.
|
|
||||||
* @param entity the persistent instance to update
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#update(Object)
|
|
||||||
*/
|
|
||||||
void update(Object entity, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the given persistent instance,
|
|
||||||
* associating it with the current Hibernate {@link org.hibernate.Session}.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the persistent instance to update
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#update(String, Object)
|
|
||||||
*/
|
|
||||||
void update(String entityName, Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the given persistent instance,
|
|
||||||
* associating it with the current Hibernate {@link org.hibernate.Session}.
|
|
||||||
* <p>Obtains the specified lock mode if the instance exists, implicitly
|
|
||||||
* checking whether the corresponding database entry still exists.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the persistent instance to update
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#update(String, Object)
|
|
||||||
*/
|
|
||||||
void update(String entityName, Object entity, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save or update the given persistent instance,
|
|
||||||
* according to its id (matching the configured "unsaved-value"?).
|
|
||||||
* Associates the instance with the current Hibernate {@link org.hibernate.Session}.
|
|
||||||
* @param entity the persistent instance to save or update
|
|
||||||
* (to be associated with the Hibernate {@code Session})
|
|
||||||
* @throws DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#saveOrUpdate(Object)
|
|
||||||
*/
|
|
||||||
void saveOrUpdate(Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save or update the given persistent instance,
|
|
||||||
* according to its id (matching the configured "unsaved-value"?).
|
|
||||||
* Associates the instance with the current Hibernate {@code Session}.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the persistent instance to save or update
|
|
||||||
* (to be associated with the Hibernate {@code Session})
|
|
||||||
* @throws DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#saveOrUpdate(String, Object)
|
|
||||||
*/
|
|
||||||
void saveOrUpdate(String entityName, Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persist the state of the given detached instance according to the
|
|
||||||
* given replication mode, reusing the current identifier value.
|
|
||||||
* @param entity the persistent object to replicate
|
|
||||||
* @param replicationMode the Hibernate ReplicationMode
|
|
||||||
* @throws DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#replicate(Object, org.hibernate.ReplicationMode)
|
|
||||||
*/
|
|
||||||
void replicate(Object entity, ReplicationMode replicationMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persist the state of the given detached instance according to the
|
|
||||||
* given replication mode, reusing the current identifier value.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the persistent object to replicate
|
|
||||||
* @param replicationMode the Hibernate ReplicationMode
|
|
||||||
* @throws DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#replicate(String, Object, org.hibernate.ReplicationMode)
|
|
||||||
*/
|
|
||||||
void replicate(String entityName, Object entity, ReplicationMode replicationMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persist the given transient instance. Follows JSR-220 semantics.
|
|
||||||
* <p>Similar to {@code save}, associating the given object
|
|
||||||
* with the current Hibernate {@link org.hibernate.Session}.
|
|
||||||
* @param entity the persistent instance to persist
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#persist(Object)
|
|
||||||
* @see #save
|
|
||||||
*/
|
|
||||||
void persist(Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persist the given transient instance. Follows JSR-220 semantics.
|
|
||||||
* <p>Similar to {@code save}, associating the given object
|
|
||||||
* with the current Hibernate {@link org.hibernate.Session}.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the persistent instance to persist
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#persist(String, Object)
|
|
||||||
* @see #save
|
|
||||||
*/
|
|
||||||
void persist(String entityName, Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy the state of the given object onto the persistent object
|
|
||||||
* with the same identifier. Follows JSR-220 semantics.
|
|
||||||
* <p>Similar to {@code saveOrUpdate}, but never associates the given
|
|
||||||
* object with the current Hibernate Session. In case of a new entity,
|
|
||||||
* the state will be copied over as well.
|
|
||||||
* <p>Note that {@code merge} will <i>not</i> update the identifiers
|
|
||||||
* in the passed-in object graph (in contrast to TopLink)! Consider
|
|
||||||
* registering Spring's {@code IdTransferringMergeEventListener} if
|
|
||||||
* you would like to have newly assigned ids transferred to the original
|
|
||||||
* object graph too.
|
|
||||||
* @param entity the object to merge with the corresponding persistence instance
|
|
||||||
* @return the updated, registered persistent instance
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#merge(Object)
|
|
||||||
* @see #saveOrUpdate
|
|
||||||
* @see org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener
|
|
||||||
*/
|
|
||||||
<T> T merge(T entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy the state of the given object onto the persistent object
|
|
||||||
* with the same identifier. Follows JSR-220 semantics.
|
|
||||||
* <p>Similar to {@code saveOrUpdate}, but never associates the given
|
|
||||||
* object with the current Hibernate {@link org.hibernate.Session}. In
|
|
||||||
* the case of a new entity, the state will be copied over as well.
|
|
||||||
* <p>Note that {@code merge} will <i>not</i> update the identifiers
|
|
||||||
* in the passed-in object graph (in contrast to TopLink)! Consider
|
|
||||||
* registering Spring's {@code IdTransferringMergeEventListener}
|
|
||||||
* if you would like to have newly assigned ids transferred to the
|
|
||||||
* original object graph too.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the object to merge with the corresponding persistence instance
|
|
||||||
* @return the updated, registered persistent instance
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#merge(String, Object)
|
|
||||||
* @see #saveOrUpdate
|
|
||||||
*/
|
|
||||||
<T> T merge(String entityName, T entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the given persistent instance.
|
|
||||||
* @param entity the persistent instance to delete
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#delete(Object)
|
|
||||||
*/
|
|
||||||
void delete(Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the given persistent instance.
|
|
||||||
* <p>Obtains the specified lock mode if the instance exists, implicitly
|
|
||||||
* checking whether the corresponding database entry still exists.
|
|
||||||
* @param entity the persistent instance to delete
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#delete(Object)
|
|
||||||
*/
|
|
||||||
void delete(Object entity, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the given persistent instance.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the persistent instance to delete
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#delete(Object)
|
|
||||||
*/
|
|
||||||
void delete(String entityName, Object entity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the given persistent instance.
|
|
||||||
* <p>Obtains the specified lock mode if the instance exists, implicitly
|
|
||||||
* checking whether the corresponding database entry still exists.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param entity the persistent instance to delete
|
|
||||||
* @param lockMode the lock mode to obtain
|
|
||||||
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#delete(Object)
|
|
||||||
*/
|
|
||||||
void delete(String entityName, Object entity, LockMode lockMode) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete all given persistent instances.
|
|
||||||
* <p>This can be combined with any of the find methods to delete by query
|
|
||||||
* in two lines of code.
|
|
||||||
* @param entities the persistent instances to delete
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#delete(Object)
|
|
||||||
*/
|
|
||||||
void deleteAll(Collection<?> entities) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flush all pending saves, updates and deletes to the database.
|
|
||||||
* <p>Only invoke this for selective eager flushing, for example when
|
|
||||||
* JDBC code needs to see certain changes within the same transaction.
|
|
||||||
* Else, it is preferable to rely on auto-flushing at transaction
|
|
||||||
* completion.
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#flush
|
|
||||||
*/
|
|
||||||
void flush() throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all objects from the {@link org.hibernate.Session} cache, and
|
|
||||||
* cancel all pending saves, updates and deletes.
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#clear
|
|
||||||
*/
|
|
||||||
void clear() throws DataAccessException;
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
// Convenience finder methods for HQL strings
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute an HQL query.
|
|
||||||
* @param queryString a query expressed in Hibernate's query language
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#createQuery
|
|
||||||
*/
|
|
||||||
List<?> find(String queryString) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute an HQL query, binding one value to a "?" parameter in the
|
|
||||||
* query string.
|
|
||||||
* @param queryString a query expressed in Hibernate's query language
|
|
||||||
* @param value the value of the parameter
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#createQuery
|
|
||||||
*/
|
|
||||||
List<?> find(String queryString, Object value) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute an HQL query, binding a number of values to "?" parameters
|
|
||||||
* in the query string.
|
|
||||||
* @param queryString a query expressed in Hibernate's query language
|
|
||||||
* @param values the values of the parameters
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#createQuery
|
|
||||||
*/
|
|
||||||
List<?> find(String queryString, Object... values) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute an HQL query, binding one value to a ":" named parameter
|
|
||||||
* in the query string.
|
|
||||||
* @param queryString a query expressed in Hibernate's query language
|
|
||||||
* @param paramName the name of the parameter
|
|
||||||
* @param value the value of the parameter
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#getNamedQuery(String)
|
|
||||||
*/
|
|
||||||
List<?> findByNamedParam(String queryString, String paramName, Object value) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute an HQL query, binding a number of values to ":" named
|
|
||||||
* parameters in the query string.
|
|
||||||
* @param queryString a query expressed in Hibernate's query language
|
|
||||||
* @param paramNames the names of the parameters
|
|
||||||
* @param values the values of the parameters
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#getNamedQuery(String)
|
|
||||||
*/
|
|
||||||
List<?> findByNamedParam(String queryString, String[] paramNames, Object[] values) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute an HQL query, binding the properties of the given bean to
|
|
||||||
* <i>named</i> parameters in the query string.
|
|
||||||
* @param queryString a query expressed in Hibernate's query language
|
|
||||||
* @param valueBean the values of the parameters
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Query#setProperties
|
|
||||||
* @see org.hibernate.Session#createQuery
|
|
||||||
*/
|
|
||||||
List<?> findByValueBean(String queryString, Object valueBean) throws DataAccessException;
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
// Convenience finder methods for named queries
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a named query.
|
|
||||||
* <p>A named query is defined in a Hibernate mapping file.
|
|
||||||
* @param queryName the name of a Hibernate query in a mapping file
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#getNamedQuery(String)
|
|
||||||
*/
|
|
||||||
List<?> findByNamedQuery(String queryName) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a named query, binding one value to a "?" parameter in
|
|
||||||
* the query string.
|
|
||||||
* <p>A named query is defined in a Hibernate mapping file.
|
|
||||||
* @param queryName the name of a Hibernate query in a mapping file
|
|
||||||
* @param value the value of the parameter
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#getNamedQuery(String)
|
|
||||||
*/
|
|
||||||
List<?> findByNamedQuery(String queryName, Object value) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a named query binding a number of values to "?" parameters
|
|
||||||
* in the query string.
|
|
||||||
* <p>A named query is defined in a Hibernate mapping file.
|
|
||||||
* @param queryName the name of a Hibernate query in a mapping file
|
|
||||||
* @param values the values of the parameters
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#getNamedQuery(String)
|
|
||||||
*/
|
|
||||||
List<?> findByNamedQuery(String queryName, Object... values) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a named query, binding one value to a ":" named parameter
|
|
||||||
* in the query string.
|
|
||||||
* <p>A named query is defined in a Hibernate mapping file.
|
|
||||||
* @param queryName the name of a Hibernate query in a mapping file
|
|
||||||
* @param paramName the name of parameter
|
|
||||||
* @param value the value of the parameter
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#getNamedQuery(String)
|
|
||||||
*/
|
|
||||||
List<?> findByNamedQueryAndNamedParam(String queryName, String paramName, Object value)
|
|
||||||
throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a named query, binding a number of values to ":" named
|
|
||||||
* parameters in the query string.
|
|
||||||
* <p>A named query is defined in a Hibernate mapping file.
|
|
||||||
* @param queryName the name of a Hibernate query in a mapping file
|
|
||||||
* @param paramNames the names of the parameters
|
|
||||||
* @param values the values of the parameters
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#getNamedQuery(String)
|
|
||||||
*/
|
|
||||||
List<?> findByNamedQueryAndNamedParam(String queryName, String[] paramNames, Object[] values)
|
|
||||||
throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a named query, binding the properties of the given bean to
|
|
||||||
* ":" named parameters in the query string.
|
|
||||||
* <p>A named query is defined in a Hibernate mapping file.
|
|
||||||
* @param queryName the name of a Hibernate query in a mapping file
|
|
||||||
* @param valueBean the values of the parameters
|
|
||||||
* @return a {@link List} containing the results of the query execution
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Query#setProperties
|
|
||||||
* @see org.hibernate.Session#getNamedQuery(String)
|
|
||||||
*/
|
|
||||||
List<?> findByNamedQueryAndValueBean(String queryName, Object valueBean) throws DataAccessException;
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
// Convenience finder methods for detached criteria
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a query based on a given Hibernate criteria object.
|
|
||||||
* @param criteria the detached Hibernate criteria object.
|
|
||||||
* <b>Note: Do not reuse criteria objects! They need to recreated per execution,
|
|
||||||
* due to the suboptimal design of Hibernate's criteria facility.</b>
|
|
||||||
* @return a {@link List} containing 0 or more persistent instances
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.criterion.DetachedCriteria#getExecutableCriteria(org.hibernate.Session)
|
|
||||||
*/
|
|
||||||
List<?> findByCriteria(DetachedCriteria criteria) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a query based on the given Hibernate criteria object.
|
|
||||||
* @param criteria the detached Hibernate criteria object.
|
|
||||||
* <b>Note: Do not reuse criteria objects! They need to recreated per execution,
|
|
||||||
* due to the suboptimal design of Hibernate's criteria facility.</b>
|
|
||||||
* @param firstResult the index of the first result object to be retrieved
|
|
||||||
* (numbered from 0)
|
|
||||||
* @param maxResults the maximum number of result objects to retrieve
|
|
||||||
* (or <=0 for no limit)
|
|
||||||
* @return a {@link List} containing 0 or more persistent instances
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.criterion.DetachedCriteria#getExecutableCriteria(org.hibernate.Session)
|
|
||||||
* @see org.hibernate.Criteria#setFirstResult(int)
|
|
||||||
* @see org.hibernate.Criteria#setMaxResults(int)
|
|
||||||
*/
|
|
||||||
List<?> findByCriteria(DetachedCriteria criteria, int firstResult, int maxResults) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a query based on the given example entity object.
|
|
||||||
* @param exampleEntity an instance of the desired entity,
|
|
||||||
* serving as example for "query-by-example"
|
|
||||||
* @return a {@link List} containing 0 or more persistent instances
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.criterion.Example#create(Object)
|
|
||||||
*/
|
|
||||||
<T> List<T> findByExample(T exampleEntity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a query based on the given example entity object.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param exampleEntity an instance of the desired entity,
|
|
||||||
* serving as example for "query-by-example"
|
|
||||||
* @return a {@link List} containing 0 or more persistent instances
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.criterion.Example#create(Object)
|
|
||||||
*/
|
|
||||||
<T> List<T> findByExample(String entityName, T exampleEntity) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a query based on a given example entity object.
|
|
||||||
* @param exampleEntity an instance of the desired entity,
|
|
||||||
* serving as example for "query-by-example"
|
|
||||||
* @param firstResult the index of the first result object to be retrieved
|
|
||||||
* (numbered from 0)
|
|
||||||
* @param maxResults the maximum number of result objects to retrieve
|
|
||||||
* (or <=0 for no limit)
|
|
||||||
* @return a {@link List} containing 0 or more persistent instances
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.criterion.Example#create(Object)
|
|
||||||
* @see org.hibernate.Criteria#setFirstResult(int)
|
|
||||||
* @see org.hibernate.Criteria#setMaxResults(int)
|
|
||||||
*/
|
|
||||||
<T> List<T> findByExample(T exampleEntity, int firstResult, int maxResults) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a query based on a given example entity object.
|
|
||||||
* @param entityName the name of the persistent entity
|
|
||||||
* @param exampleEntity an instance of the desired entity,
|
|
||||||
* serving as example for "query-by-example"
|
|
||||||
* @param firstResult the index of the first result object to be retrieved
|
|
||||||
* (numbered from 0)
|
|
||||||
* @param maxResults the maximum number of result objects to retrieve
|
|
||||||
* (or <=0 for no limit)
|
|
||||||
* @return a {@link List} containing 0 or more persistent instances
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.criterion.Example#create(Object)
|
|
||||||
* @see org.hibernate.Criteria#setFirstResult(int)
|
|
||||||
* @see org.hibernate.Criteria#setMaxResults(int)
|
|
||||||
*/
|
|
||||||
<T> List<T> findByExample(String entityName, T exampleEntity, int firstResult, int maxResults)
|
|
||||||
throws DataAccessException;
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
// Convenience query methods for iteration and bulk updates/deletes
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a query for persistent instances.
|
|
||||||
* <p>Returns the results as an {@link Iterator}. Entities returned are
|
|
||||||
* initialized on demand. See the Hibernate API documentation for details.
|
|
||||||
* @param queryString a query expressed in Hibernate's query language
|
|
||||||
* @return an {@link Iterator} containing 0 or more persistent instances
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#createQuery
|
|
||||||
* @see org.hibernate.Query#iterate
|
|
||||||
*/
|
|
||||||
Iterator<?> iterate(String queryString) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a query for persistent instances, binding one value
|
|
||||||
* to a "?" parameter in the query string.
|
|
||||||
* <p>Returns the results as an {@link Iterator}. Entities returned are
|
|
||||||
* initialized on demand. See the Hibernate API documentation for details.
|
|
||||||
* @param queryString a query expressed in Hibernate's query language
|
|
||||||
* @param value the value of the parameter
|
|
||||||
* @return an {@link Iterator} containing 0 or more persistent instances
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#createQuery
|
|
||||||
* @see org.hibernate.Query#iterate
|
|
||||||
*/
|
|
||||||
Iterator<?> iterate(String queryString, Object value) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a query for persistent instances, binding a number of
|
|
||||||
* values to "?" parameters in the query string.
|
|
||||||
* <p>Returns the results as an {@link Iterator}. Entities returned are
|
|
||||||
* initialized on demand. See the Hibernate API documentation for details.
|
|
||||||
* @param queryString a query expressed in Hibernate's query language
|
|
||||||
* @param values the values of the parameters
|
|
||||||
* @return an {@link Iterator} containing 0 or more persistent instances
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#createQuery
|
|
||||||
* @see org.hibernate.Query#iterate
|
|
||||||
*/
|
|
||||||
Iterator<?> iterate(String queryString, Object... values) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Immediately close an {@link Iterator} created by any of the various
|
|
||||||
* {@code iterate(..)} operations, instead of waiting until the
|
|
||||||
* session is closed or disconnected.
|
|
||||||
* @param it the {@code Iterator} to close
|
|
||||||
* @throws DataAccessException if the {@code Iterator} could not be closed
|
|
||||||
* @see org.hibernate.Hibernate#close
|
|
||||||
*/
|
|
||||||
void closeIterator(Iterator<?> it) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update/delete all objects according to the given query.
|
|
||||||
* @param queryString an update/delete query expressed in Hibernate's query language
|
|
||||||
* @return the number of instances updated/deleted
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#createQuery
|
|
||||||
* @see org.hibernate.Query#executeUpdate
|
|
||||||
*/
|
|
||||||
int bulkUpdate(String queryString) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update/delete all objects according to the given query, binding one value
|
|
||||||
* to a "?" parameter in the query string.
|
|
||||||
* @param queryString an update/delete query expressed in Hibernate's query language
|
|
||||||
* @param value the value of the parameter
|
|
||||||
* @return the number of instances updated/deleted
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#createQuery
|
|
||||||
* @see org.hibernate.Query#executeUpdate
|
|
||||||
*/
|
|
||||||
int bulkUpdate(String queryString, Object value) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update/delete all objects according to the given query, binding a number of
|
|
||||||
* values to "?" parameters in the query string.
|
|
||||||
* @param queryString an update/delete query expressed in Hibernate's query language
|
|
||||||
* @param values the values of the parameters
|
|
||||||
* @return the number of instances updated/deleted
|
|
||||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
|
||||||
* @see org.hibernate.Session#createQuery
|
|
||||||
* @see org.hibernate.Query#executeUpdate
|
|
||||||
*/
|
|
||||||
int bulkUpdate(String queryString, Object... values) throws DataAccessException;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2013 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import org.hibernate.OptimisticLockException;
|
|
||||||
import org.hibernate.StaleObjectStateException;
|
|
||||||
import org.hibernate.StaleStateException;
|
|
||||||
|
|
||||||
import org.springframework.orm.ObjectOptimisticLockingFailureException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate-specific subclass of ObjectOptimisticLockingFailureException.
|
|
||||||
* Converts Hibernate's StaleObjectStateException, StaleStateException
|
|
||||||
* and OptimisticLockException.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class HibernateOptimisticLockingFailureException extends ObjectOptimisticLockingFailureException {
|
|
||||||
|
|
||||||
public HibernateOptimisticLockingFailureException(StaleObjectStateException ex) {
|
|
||||||
super(ex.getEntityName(), ex.getIdentifier(), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HibernateOptimisticLockingFailureException(StaleStateException ex) {
|
|
||||||
super(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HibernateOptimisticLockingFailureException(OptimisticLockException ex) {
|
|
||||||
super(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import org.hibernate.QueryException;
|
|
||||||
|
|
||||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate-specific subclass of InvalidDataAccessResourceUsageException,
|
|
||||||
* thrown on invalid HQL query syntax.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class HibernateQueryException extends InvalidDataAccessResourceUsageException {
|
|
||||||
|
|
||||||
public HibernateQueryException(QueryException ex) {
|
|
||||||
super(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the HQL query string that was invalid.
|
|
||||||
*/
|
|
||||||
public String getQueryString() {
|
|
||||||
return ((QueryException) getCause()).getQueryString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
|
|
||||||
import org.springframework.dao.UncategorizedDataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate-specific subclass of UncategorizedDataAccessException,
|
|
||||||
* for Hibernate system errors that do not match any concrete
|
|
||||||
* {@code org.springframework.dao} exceptions.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class HibernateSystemException extends UncategorizedDataAccessException {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new HibernateSystemException,
|
|
||||||
* wrapping an arbitrary HibernateException.
|
|
||||||
* @param cause the HibernateException thrown
|
|
||||||
*/
|
|
||||||
public HibernateSystemException(HibernateException cause) {
|
|
||||||
super(cause != null ? cause.getMessage() : null, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,933 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
|
|
||||||
import org.hibernate.ConnectionReleaseMode;
|
|
||||||
import org.hibernate.FlushMode;
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.Interceptor;
|
|
||||||
import org.hibernate.JDBCException;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
import org.hibernate.Transaction;
|
|
||||||
import org.hibernate.exception.GenericJDBCException;
|
|
||||||
import org.hibernate.impl.SessionImpl;
|
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
|
||||||
import org.springframework.beans.factory.BeanFactoryAware;
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
import org.springframework.dao.DataAccessException;
|
|
||||||
import org.springframework.dao.DataAccessResourceFailureException;
|
|
||||||
import org.springframework.jdbc.datasource.ConnectionHolder;
|
|
||||||
import org.springframework.jdbc.datasource.DataSourceUtils;
|
|
||||||
import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport;
|
|
||||||
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
|
|
||||||
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
|
|
||||||
import org.springframework.jdbc.support.SQLExceptionTranslator;
|
|
||||||
import org.springframework.transaction.CannotCreateTransactionException;
|
|
||||||
import org.springframework.transaction.IllegalTransactionStateException;
|
|
||||||
import org.springframework.transaction.InvalidIsolationLevelException;
|
|
||||||
import org.springframework.transaction.TransactionDefinition;
|
|
||||||
import org.springframework.transaction.TransactionSystemException;
|
|
||||||
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
|
|
||||||
import org.springframework.transaction.support.DefaultTransactionStatus;
|
|
||||||
import org.springframework.transaction.support.ResourceTransactionManager;
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link org.springframework.transaction.PlatformTransactionManager}
|
|
||||||
* implementation for a single Hibernate {@link org.hibernate.SessionFactory}.
|
|
||||||
* Binds a Hibernate Session from the specified factory to the thread, potentially
|
|
||||||
* allowing for one thread-bound Session per factory. {@link SessionFactoryUtils}
|
|
||||||
* and {@link HibernateTemplate} are aware of thread-bound Sessions and participate
|
|
||||||
* in such transactions automatically. Using either of those or going through
|
|
||||||
* {@code SessionFactory.getCurrentSession()} is required for Hibernate
|
|
||||||
* access code that needs to support this transaction handling mechanism.
|
|
||||||
*
|
|
||||||
* <p>Supports custom isolation levels, and timeouts that get applied as
|
|
||||||
* Hibernate transaction timeouts.
|
|
||||||
*
|
|
||||||
* <p>This transaction manager is appropriate for applications that use a single
|
|
||||||
* Hibernate SessionFactory for transactional data access, but it also supports
|
|
||||||
* direct DataSource access within a transaction (i.e. plain JDBC code working
|
|
||||||
* with the same DataSource). This allows for mixing services which access Hibernate
|
|
||||||
* and services which use plain JDBC (without being aware of Hibernate)!
|
|
||||||
* Application code needs to stick to the same simple Connection lookup pattern as
|
|
||||||
* with {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
|
|
||||||
* (i.e. {@link org.springframework.jdbc.datasource.DataSourceUtils#getConnection}
|
|
||||||
* or going through a
|
|
||||||
* {@link org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy}).
|
|
||||||
*
|
|
||||||
* <p>Note: To be able to register a DataSource's Connection for plain JDBC code,
|
|
||||||
* this instance needs to be aware of the DataSource ({@link #setDataSource}).
|
|
||||||
* The given DataSource should obviously match the one used by the given
|
|
||||||
* SessionFactory. To achieve this, configure both to the same JNDI DataSource,
|
|
||||||
* or preferably create the SessionFactory with {@link LocalSessionFactoryBean} and
|
|
||||||
* a local DataSource (which will be autodetected by this transaction manager).
|
|
||||||
*
|
|
||||||
* <p>JTA (usually through {@link org.springframework.transaction.jta.JtaTransactionManager})
|
|
||||||
* is necessary for accessing multiple transactional resources within the same
|
|
||||||
* transaction. The DataSource that Hibernate uses needs to be JTA-enabled in
|
|
||||||
* such a scenario (see container setup). Normally, JTA setup for Hibernate is
|
|
||||||
* somewhat container-specific due to the JTA TransactionManager lookup, required
|
|
||||||
* for proper transactional handling of the SessionFactory-level read-write cache.
|
|
||||||
*
|
|
||||||
* <p>Fortunately, there is an easier way with Spring: {@link SessionFactoryUtils}
|
|
||||||
* (and thus {@link HibernateTemplate}) registers synchronizations with Spring's
|
|
||||||
* {@link org.springframework.transaction.support.TransactionSynchronizationManager}
|
|
||||||
* (as used by {@link org.springframework.transaction.jta.JtaTransactionManager}),
|
|
||||||
* for proper after-completion callbacks. Therefore, as long as Spring's
|
|
||||||
* JtaTransactionManager drives the JTA transactions, Hibernate does not require
|
|
||||||
* any special configuration for proper JTA participation. Note that there are
|
|
||||||
* special restrictions with EJB CMT and restrictive JTA subsystems: See
|
|
||||||
* {@link org.springframework.transaction.jta.JtaTransactionManager}'s javadoc for details.
|
|
||||||
*
|
|
||||||
* <p>This transaction manager supports nested transactions via JDBC 3.0 Savepoints.
|
|
||||||
* The {@link #setNestedTransactionAllowed} "nestedTransactionAllowed"} flag defaults
|
|
||||||
* to "false", though, as nested transactions will just apply to the JDBC Connection,
|
|
||||||
* not to the Hibernate Session and its cached entity objects and related context.
|
|
||||||
* You can manually set the flag to "true" if you want to use nested transactions
|
|
||||||
* for JDBC access code which participates in Hibernate transactions (provided that
|
|
||||||
* your JDBC driver supports Savepoints). <i>Note that Hibernate itself does not
|
|
||||||
* support nested transactions! Hence, do not expect Hibernate access code to
|
|
||||||
* semantically participate in a nested transaction.</i>
|
|
||||||
*
|
|
||||||
* <p>Requires Hibernate 3.6.x, as of Spring 4.0.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see #setSessionFactory
|
|
||||||
* @see #setDataSource
|
|
||||||
* @see LocalSessionFactoryBean
|
|
||||||
* @see SessionFactoryUtils#getSession
|
|
||||||
* @see SessionFactoryUtils#applyTransactionTimeout
|
|
||||||
* @see SessionFactoryUtils#releaseSession
|
|
||||||
* @see HibernateTemplate
|
|
||||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection
|
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#applyTransactionTimeout
|
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection
|
|
||||||
* @see org.springframework.jdbc.core.JdbcTemplate
|
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
|
|
||||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class HibernateTransactionManager extends AbstractPlatformTransactionManager
|
|
||||||
implements ResourceTransactionManager, BeanFactoryAware, InitializingBean {
|
|
||||||
|
|
||||||
private SessionFactory sessionFactory;
|
|
||||||
|
|
||||||
private DataSource dataSource;
|
|
||||||
|
|
||||||
private boolean autodetectDataSource = true;
|
|
||||||
|
|
||||||
private boolean prepareConnection = true;
|
|
||||||
|
|
||||||
private boolean hibernateManagedSession = false;
|
|
||||||
|
|
||||||
private boolean earlyFlushBeforeCommit = false;
|
|
||||||
|
|
||||||
private Object entityInterceptor;
|
|
||||||
|
|
||||||
private SQLExceptionTranslator jdbcExceptionTranslator;
|
|
||||||
|
|
||||||
private SQLExceptionTranslator defaultJdbcExceptionTranslator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Just needed for entityInterceptorBeanName.
|
|
||||||
* @see #setEntityInterceptorBeanName
|
|
||||||
*/
|
|
||||||
private BeanFactory beanFactory;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new HibernateTransactionManager instance.
|
|
||||||
* A SessionFactory has to be set to be able to use it.
|
|
||||||
* @see #setSessionFactory
|
|
||||||
*/
|
|
||||||
public HibernateTransactionManager() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new HibernateTransactionManager instance.
|
|
||||||
* @param sessionFactory SessionFactory to manage transactions for
|
|
||||||
*/
|
|
||||||
public HibernateTransactionManager(SessionFactory sessionFactory) {
|
|
||||||
this.sessionFactory = sessionFactory;
|
|
||||||
afterPropertiesSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the SessionFactory that this instance should manage transactions for.
|
|
||||||
*/
|
|
||||||
public void setSessionFactory(SessionFactory sessionFactory) {
|
|
||||||
this.sessionFactory = sessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the SessionFactory that this instance should manage transactions for.
|
|
||||||
*/
|
|
||||||
public SessionFactory getSessionFactory() {
|
|
||||||
return this.sessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the JDBC DataSource that this instance should manage transactions for.
|
|
||||||
* The DataSource should match the one used by the Hibernate SessionFactory:
|
|
||||||
* for example, you could specify the same JNDI DataSource for both.
|
|
||||||
* <p>If the SessionFactory was configured with LocalDataSourceConnectionProvider,
|
|
||||||
* i.e. by Spring's LocalSessionFactoryBean with a specified "dataSource",
|
|
||||||
* the DataSource will be auto-detected: You can still explicitly specify the
|
|
||||||
* DataSource, but you don't need to in this case.
|
|
||||||
* <p>A transactional JDBC Connection for this DataSource will be provided to
|
|
||||||
* application code accessing this DataSource directly via DataSourceUtils
|
|
||||||
* or JdbcTemplate. The Connection will be taken from the Hibernate Session.
|
|
||||||
* <p>The DataSource specified here should be the target DataSource to manage
|
|
||||||
* transactions for, not a TransactionAwareDataSourceProxy. Only data access
|
|
||||||
* code may work with TransactionAwareDataSourceProxy, while the transaction
|
|
||||||
* manager needs to work on the underlying target DataSource. If there's
|
|
||||||
* nevertheless a TransactionAwareDataSourceProxy passed in, it will be
|
|
||||||
* unwrapped to extract its target DataSource.
|
|
||||||
* @see #setAutodetectDataSource
|
|
||||||
* @see LocalDataSourceConnectionProvider
|
|
||||||
* @see LocalSessionFactoryBean#setDataSource
|
|
||||||
* @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
|
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceUtils
|
|
||||||
* @see org.springframework.jdbc.core.JdbcTemplate
|
|
||||||
*/
|
|
||||||
public void setDataSource(DataSource dataSource) {
|
|
||||||
if (dataSource instanceof TransactionAwareDataSourceProxy) {
|
|
||||||
// If we got a TransactionAwareDataSourceProxy, we need to perform transactions
|
|
||||||
// for its underlying target DataSource, else data access code won't see
|
|
||||||
// properly exposed transactions (i.e. transactions for the target DataSource).
|
|
||||||
this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.dataSource = dataSource;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the JDBC DataSource that this instance manages transactions for.
|
|
||||||
*/
|
|
||||||
public DataSource getDataSource() {
|
|
||||||
return this.dataSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether to autodetect a JDBC DataSource used by the Hibernate SessionFactory,
|
|
||||||
* if set via LocalSessionFactoryBean's {@code setDataSource}. Default is "true".
|
|
||||||
* <p>Can be turned off to deliberately ignore an available DataSource, in order
|
|
||||||
* to not expose Hibernate transactions as JDBC transactions for that DataSource.
|
|
||||||
* @see #setDataSource
|
|
||||||
* @see LocalSessionFactoryBean#setDataSource
|
|
||||||
*/
|
|
||||||
public void setAutodetectDataSource(boolean autodetectDataSource) {
|
|
||||||
this.autodetectDataSource = autodetectDataSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether to prepare the underlying JDBC Connection of a transactional
|
|
||||||
* Hibernate Session, that is, whether to apply a transaction-specific
|
|
||||||
* isolation level and/or the transaction's read-only flag to the underlying
|
|
||||||
* JDBC Connection.
|
|
||||||
* <p>Default is "true". If you turn this flag off, the transaction manager
|
|
||||||
* will not support per-transaction isolation levels anymore. It will not
|
|
||||||
* call {@code Connection.setReadOnly(true)} for read-only transactions
|
|
||||||
* anymore either. If this flag is turned off, no cleanup of a JDBC Connection
|
|
||||||
* is required after a transaction, since no Connection settings will get modified.
|
|
||||||
* @see java.sql.Connection#setTransactionIsolation
|
|
||||||
* @see java.sql.Connection#setReadOnly
|
|
||||||
*/
|
|
||||||
public void setPrepareConnection(boolean prepareConnection) {
|
|
||||||
this.prepareConnection = prepareConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether to operate on a Hibernate-managed Session instead of a
|
|
||||||
* Spring-managed Session, that is, whether to obtain the Session through
|
|
||||||
* Hibernate's {@link org.hibernate.SessionFactory#getCurrentSession()}
|
|
||||||
* instead of {@link org.hibernate.SessionFactory#openSession()} (with a Spring
|
|
||||||
* {@link org.springframework.transaction.support.TransactionSynchronizationManager}
|
|
||||||
* check preceding it).
|
|
||||||
* <p>Default is "false", i.e. using a Spring-managed Session: taking the current
|
|
||||||
* thread-bound Session if available (e.g. in an Open-Session-in-View scenario),
|
|
||||||
* creating a new Session for the current transaction otherwise.
|
|
||||||
* <p>Switch this flag to "true" in order to enforce use of a Hibernate-managed Session.
|
|
||||||
* Note that this requires {@link org.hibernate.SessionFactory#getCurrentSession()}
|
|
||||||
* to always return a proper Session when called for a Spring-managed transaction;
|
|
||||||
* transaction begin will fail if the {@code getCurrentSession()} call fails.
|
|
||||||
* <p>This mode will typically be used in combination with a custom Hibernate
|
|
||||||
* {@link org.hibernate.context.CurrentSessionContext} implementation that stores
|
|
||||||
* Sessions in a place other than Spring's TransactionSynchronizationManager.
|
|
||||||
* It may also be used in combination with Spring's Open-Session-in-View support
|
|
||||||
* (using Spring's default {@link SpringSessionContext}), in which case it subtly
|
|
||||||
* differs from the Spring-managed Session mode: The pre-bound Session will <i>not</i>
|
|
||||||
* receive a {@code clear()} call (on rollback) or a {@code disconnect()}
|
|
||||||
* call (on transaction completion) in such a scenario; this is rather left up
|
|
||||||
* to a custom CurrentSessionContext implementation (if desired).
|
|
||||||
*/
|
|
||||||
public void setHibernateManagedSession(boolean hibernateManagedSession) {
|
|
||||||
this.hibernateManagedSession = hibernateManagedSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether to perform an early flush before proceeding with a commit.
|
|
||||||
* <p>Default is "false", performing an implicit flush as part of the actual
|
|
||||||
* commit step. Switch this to "true" in order to enforce an explicit early
|
|
||||||
* flush right <i>before</i> the actual commit step.
|
|
||||||
* <p>An early flush happens before the before-commit synchronization phase,
|
|
||||||
* making flushed state visible to {@code beforeCommit} callbacks of registered
|
|
||||||
* {@link org.springframework.transaction.support.TransactionSynchronization}
|
|
||||||
* objects. Such explicit flush behavior is consistent with Spring-driven
|
|
||||||
* flushing in a JTA transaction environment, so may also get enforced for
|
|
||||||
* consistency with JTA transaction behavior.
|
|
||||||
* @see #prepareForCommit
|
|
||||||
*/
|
|
||||||
public void setEarlyFlushBeforeCommit(boolean earlyFlushBeforeCommit) {
|
|
||||||
this.earlyFlushBeforeCommit = earlyFlushBeforeCommit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the bean name of a Hibernate entity interceptor that allows to inspect
|
|
||||||
* and change property values before writing to and reading from the database.
|
|
||||||
* Will get applied to any new Session created by this transaction manager.
|
|
||||||
* <p>Requires the bean factory to be known, to be able to resolve the bean
|
|
||||||
* name to an interceptor instance on session creation. Typically used for
|
|
||||||
* prototype interceptors, i.e. a new interceptor instance per session.
|
|
||||||
* <p>Can also be used for shared interceptor instances, but it is recommended
|
|
||||||
* to set the interceptor reference directly in such a scenario.
|
|
||||||
* @param entityInterceptorBeanName the name of the entity interceptor in
|
|
||||||
* the bean factory
|
|
||||||
* @see #setBeanFactory
|
|
||||||
* @see #setEntityInterceptor
|
|
||||||
*/
|
|
||||||
public void setEntityInterceptorBeanName(String entityInterceptorBeanName) {
|
|
||||||
this.entityInterceptor = entityInterceptorBeanName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a Hibernate entity interceptor that allows to inspect and change
|
|
||||||
* property values before writing to and reading from the database.
|
|
||||||
* Will get applied to any new Session created by this transaction manager.
|
|
||||||
* <p>Such an interceptor can either be set at the SessionFactory level,
|
|
||||||
* i.e. on LocalSessionFactoryBean, or at the Session level, i.e. on
|
|
||||||
* HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager.
|
|
||||||
* It's preferable to set it on LocalSessionFactoryBean or HibernateTransactionManager
|
|
||||||
* to avoid repeated configuration and guarantee consistent behavior in transactions.
|
|
||||||
* @see LocalSessionFactoryBean#setEntityInterceptor
|
|
||||||
* @see HibernateTemplate#setEntityInterceptor
|
|
||||||
* @see HibernateInterceptor#setEntityInterceptor
|
|
||||||
*/
|
|
||||||
public void setEntityInterceptor(Interceptor entityInterceptor) {
|
|
||||||
this.entityInterceptor = entityInterceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the current Hibernate entity interceptor, or {@code null} if none.
|
|
||||||
* Resolves an entity interceptor bean name via the bean factory,
|
|
||||||
* if necessary.
|
|
||||||
* @throws IllegalStateException if bean name specified but no bean factory set
|
|
||||||
* @throws BeansException if bean name resolution via the bean factory failed
|
|
||||||
* @see #setEntityInterceptor
|
|
||||||
* @see #setEntityInterceptorBeanName
|
|
||||||
* @see #setBeanFactory
|
|
||||||
*/
|
|
||||||
public Interceptor getEntityInterceptor() throws IllegalStateException, BeansException {
|
|
||||||
if (this.entityInterceptor instanceof Interceptor) {
|
|
||||||
return (Interceptor) entityInterceptor;
|
|
||||||
}
|
|
||||||
else if (this.entityInterceptor instanceof String) {
|
|
||||||
if (this.beanFactory == null) {
|
|
||||||
throw new IllegalStateException("Cannot get entity interceptor via bean name if no bean factory set");
|
|
||||||
}
|
|
||||||
String beanName = (String) this.entityInterceptor;
|
|
||||||
return this.beanFactory.getBean(beanName, Interceptor.class);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the JDBC exception translator for this transaction manager.
|
|
||||||
* <p>Applied to any SQLException root cause of a Hibernate JDBCException that
|
|
||||||
* is thrown on flush, overriding Hibernate's default SQLException translation
|
|
||||||
* (which is based on Hibernate's Dialect for a specific target database).
|
|
||||||
* @param jdbcExceptionTranslator the exception translator
|
|
||||||
* @see java.sql.SQLException
|
|
||||||
* @see org.hibernate.JDBCException
|
|
||||||
* @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
|
|
||||||
* @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
|
|
||||||
*/
|
|
||||||
public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
|
|
||||||
this.jdbcExceptionTranslator = jdbcExceptionTranslator;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the JDBC exception translator for this transaction manager, if any.
|
|
||||||
*/
|
|
||||||
public SQLExceptionTranslator getJdbcExceptionTranslator() {
|
|
||||||
return this.jdbcExceptionTranslator;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The bean factory just needs to be known for resolving entity interceptor
|
|
||||||
* bean names. It does not need to be set for any other mode of operation.
|
|
||||||
* @see #setEntityInterceptorBeanName
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void setBeanFactory(BeanFactory beanFactory) {
|
|
||||||
this.beanFactory = beanFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterPropertiesSet() {
|
|
||||||
if (getSessionFactory() == null) {
|
|
||||||
throw new IllegalArgumentException("Property 'sessionFactory' is required");
|
|
||||||
}
|
|
||||||
if (this.entityInterceptor instanceof String && this.beanFactory == null) {
|
|
||||||
throw new IllegalArgumentException("Property 'beanFactory' is required for 'entityInterceptorBeanName'");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for SessionFactory's DataSource.
|
|
||||||
if (this.autodetectDataSource && getDataSource() == null) {
|
|
||||||
DataSource sfds = SessionFactoryUtils.getDataSource(getSessionFactory());
|
|
||||||
if (sfds != null) {
|
|
||||||
// Use the SessionFactory's DataSource for exposing transactions to JDBC code.
|
|
||||||
if (logger.isInfoEnabled()) {
|
|
||||||
logger.info("Using DataSource [" + sfds +
|
|
||||||
"] of Hibernate SessionFactory for HibernateTransactionManager");
|
|
||||||
}
|
|
||||||
setDataSource(sfds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getResourceFactory() {
|
|
||||||
return getSessionFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Object doGetTransaction() {
|
|
||||||
HibernateTransactionObject txObject = new HibernateTransactionObject();
|
|
||||||
txObject.setSavepointAllowed(isNestedTransactionAllowed());
|
|
||||||
|
|
||||||
SessionHolder sessionHolder =
|
|
||||||
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
|
|
||||||
if (sessionHolder != null) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Found thread-bound Session [" +
|
|
||||||
SessionFactoryUtils.toString(sessionHolder.getSession()) + "] for Hibernate transaction");
|
|
||||||
}
|
|
||||||
txObject.setSessionHolder(sessionHolder);
|
|
||||||
}
|
|
||||||
else if (this.hibernateManagedSession) {
|
|
||||||
try {
|
|
||||||
Session session = getSessionFactory().getCurrentSession();
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Found Hibernate-managed Session [" +
|
|
||||||
SessionFactoryUtils.toString(session) + "] for Spring-managed transaction");
|
|
||||||
}
|
|
||||||
txObject.setExistingSession(session);
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
throw new DataAccessResourceFailureException(
|
|
||||||
"Could not obtain Hibernate-managed Session for Spring-managed transaction", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getDataSource() != null) {
|
|
||||||
ConnectionHolder conHolder = (ConnectionHolder)
|
|
||||||
TransactionSynchronizationManager.getResource(getDataSource());
|
|
||||||
txObject.setConnectionHolder(conHolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
return txObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isExistingTransaction(Object transaction) {
|
|
||||||
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
|
|
||||||
return (txObject.hasSpringManagedTransaction() ||
|
|
||||||
(this.hibernateManagedSession && txObject.hasHibernateManagedTransaction()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doBegin(Object transaction, TransactionDefinition definition) {
|
|
||||||
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
|
|
||||||
|
|
||||||
if (txObject.hasConnectionHolder() && !txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
|
|
||||||
throw new IllegalTransactionStateException(
|
|
||||||
"Pre-bound JDBC Connection found! HibernateTransactionManager does not support " +
|
|
||||||
"running within DataSourceTransactionManager if told to manage the DataSource itself. " +
|
|
||||||
"It is recommended to use a single HibernateTransactionManager for all transactions " +
|
|
||||||
"on a single DataSource, no matter whether Hibernate or JDBC access.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Session session = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
|
|
||||||
Interceptor entityInterceptor = getEntityInterceptor();
|
|
||||||
Session newSession = (entityInterceptor != null ?
|
|
||||||
getSessionFactory().openSession(entityInterceptor) : getSessionFactory().openSession());
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Opened new Session [" + SessionFactoryUtils.toString(newSession) +
|
|
||||||
"] for Hibernate transaction");
|
|
||||||
}
|
|
||||||
txObject.setSession(newSession);
|
|
||||||
}
|
|
||||||
|
|
||||||
session = txObject.getSessionHolder().getSession();
|
|
||||||
|
|
||||||
if (this.prepareConnection && isSameConnectionForEntireSession(session)) {
|
|
||||||
// We're allowed to change the transaction settings of the JDBC Connection.
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug(
|
|
||||||
"Preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");
|
|
||||||
}
|
|
||||||
Connection con = session.connection();
|
|
||||||
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
|
|
||||||
txObject.setPreviousIsolationLevel(previousIsolationLevel);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Not allowed to change the transaction settings of the JDBC Connection.
|
|
||||||
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
|
|
||||||
// We should set a specific isolation level but are not allowed to...
|
|
||||||
throw new InvalidIsolationLevelException(
|
|
||||||
"HibernateTransactionManager is not allowed to support custom isolation levels: " +
|
|
||||||
"make sure that its 'prepareConnection' flag is on (the default) and that the " +
|
|
||||||
"Hibernate connection release mode is set to 'on_close' (SpringTransactionFactory's default). " +
|
|
||||||
"Make sure that your LocalSessionFactoryBean actually uses SpringTransactionFactory: Your " +
|
|
||||||
"Hibernate properties should *not* include a 'hibernate.transaction.factory_class' property!");
|
|
||||||
}
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug(
|
|
||||||
"Not preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (definition.isReadOnly() && txObject.isNewSession()) {
|
|
||||||
// Just set to MANUAL in case of a new Session for this transaction.
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!definition.isReadOnly() && !txObject.isNewSession()) {
|
|
||||||
// We need AUTO or COMMIT for a non-read-only transaction.
|
|
||||||
FlushMode flushMode = session.getFlushMode();
|
|
||||||
if (flushMode.lessThan(FlushMode.COMMIT)) {
|
|
||||||
session.setFlushMode(FlushMode.AUTO);
|
|
||||||
txObject.getSessionHolder().setPreviousFlushMode(flushMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Transaction hibTx;
|
|
||||||
|
|
||||||
// Register transaction timeout.
|
|
||||||
int timeout = determineTimeout(definition);
|
|
||||||
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
|
|
||||||
// Use Hibernate's own transaction timeout mechanism on Hibernate 3.1+
|
|
||||||
// Applies to all statements, also to inserts, updates and deletes!
|
|
||||||
hibTx = session.getTransaction();
|
|
||||||
hibTx.setTimeout(timeout);
|
|
||||||
hibTx.begin();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Open a plain Hibernate transaction without specified timeout.
|
|
||||||
hibTx = session.beginTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the Hibernate transaction to the session holder.
|
|
||||||
txObject.getSessionHolder().setTransaction(hibTx);
|
|
||||||
|
|
||||||
// Register the Hibernate Session's JDBC Connection for the DataSource, if set.
|
|
||||||
if (getDataSource() != null) {
|
|
||||||
Connection con = session.connection();
|
|
||||||
ConnectionHolder conHolder = new ConnectionHolder(con);
|
|
||||||
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
|
|
||||||
conHolder.setTimeoutInSeconds(timeout);
|
|
||||||
}
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Exposing Hibernate transaction as JDBC transaction [" + con + "]");
|
|
||||||
}
|
|
||||||
TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);
|
|
||||||
txObject.setConnectionHolder(conHolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind the session holder to the thread.
|
|
||||||
if (txObject.isNewSessionHolder()) {
|
|
||||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder());
|
|
||||||
}
|
|
||||||
txObject.getSessionHolder().setSynchronizedWithTransaction(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Throwable ex) {
|
|
||||||
if (txObject.isNewSession()) {
|
|
||||||
try {
|
|
||||||
if (session.getTransaction().isActive()) {
|
|
||||||
session.getTransaction().rollback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Throwable ex2) {
|
|
||||||
logger.debug("Could not rollback Session after failed transaction begin", ex);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
SessionFactoryUtils.closeSession(session);
|
|
||||||
txObject.setSessionHolder(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Object doSuspend(Object transaction) {
|
|
||||||
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
|
|
||||||
txObject.setSessionHolder(null);
|
|
||||||
SessionHolder sessionHolder =
|
|
||||||
(SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
|
||||||
txObject.setConnectionHolder(null);
|
|
||||||
ConnectionHolder connectionHolder = null;
|
|
||||||
if (getDataSource() != null) {
|
|
||||||
connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.unbindResource(getDataSource());
|
|
||||||
}
|
|
||||||
return new SuspendedResourcesHolder(sessionHolder, connectionHolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doResume(Object transaction, Object suspendedResources) {
|
|
||||||
SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources;
|
|
||||||
if (TransactionSynchronizationManager.hasResource(getSessionFactory())) {
|
|
||||||
// From non-transactional code running in active transaction synchronization
|
|
||||||
// -> can be safely removed, will be closed on transaction completion.
|
|
||||||
TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
|
||||||
}
|
|
||||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), resourcesHolder.getSessionHolder());
|
|
||||||
if (getDataSource() != null) {
|
|
||||||
TransactionSynchronizationManager.bindResource(getDataSource(), resourcesHolder.getConnectionHolder());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void prepareForCommit(DefaultTransactionStatus status) {
|
|
||||||
if (this.earlyFlushBeforeCommit && status.isNewTransaction()) {
|
|
||||||
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
|
|
||||||
Session session = txObject.getSessionHolder().getSession();
|
|
||||||
if (!session.getFlushMode().lessThan(FlushMode.COMMIT)) {
|
|
||||||
logger.debug("Performing an early flush for Hibernate transaction");
|
|
||||||
try {
|
|
||||||
session.flush();
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
throw convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doCommit(DefaultTransactionStatus status) {
|
|
||||||
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
|
|
||||||
if (status.isDebug()) {
|
|
||||||
logger.debug("Committing Hibernate transaction on Session [" +
|
|
||||||
SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "]");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
txObject.getSessionHolder().getTransaction().commit();
|
|
||||||
}
|
|
||||||
catch (org.hibernate.TransactionException ex) {
|
|
||||||
// assumably from commit call to the underlying JDBC connection
|
|
||||||
throw new TransactionSystemException("Could not commit Hibernate transaction", ex);
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
// assumably failed to flush changes to database
|
|
||||||
throw convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doRollback(DefaultTransactionStatus status) {
|
|
||||||
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
|
|
||||||
if (status.isDebug()) {
|
|
||||||
logger.debug("Rolling back Hibernate transaction on Session [" +
|
|
||||||
SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "]");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
txObject.getSessionHolder().getTransaction().rollback();
|
|
||||||
}
|
|
||||||
catch (org.hibernate.TransactionException ex) {
|
|
||||||
throw new TransactionSystemException("Could not roll back Hibernate transaction", ex);
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
// Shouldn't really happen, as a rollback doesn't cause a flush.
|
|
||||||
throw convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if (!txObject.isNewSession() && !this.hibernateManagedSession) {
|
|
||||||
// Clear all pending inserts/updates/deletes in the Session.
|
|
||||||
// Necessary for pre-bound Sessions, to avoid inconsistent state.
|
|
||||||
txObject.getSessionHolder().getSession().clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doSetRollbackOnly(DefaultTransactionStatus status) {
|
|
||||||
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
|
|
||||||
if (status.isDebug()) {
|
|
||||||
logger.debug("Setting Hibernate transaction on Session [" +
|
|
||||||
SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "] rollback-only");
|
|
||||||
}
|
|
||||||
txObject.setRollbackOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doCleanupAfterCompletion(Object transaction) {
|
|
||||||
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
|
|
||||||
|
|
||||||
// Remove the session holder from the thread.
|
|
||||||
if (txObject.isNewSessionHolder()) {
|
|
||||||
TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the JDBC connection holder from the thread, if exposed.
|
|
||||||
if (getDataSource() != null) {
|
|
||||||
TransactionSynchronizationManager.unbindResource(getDataSource());
|
|
||||||
}
|
|
||||||
|
|
||||||
Session session = txObject.getSessionHolder().getSession();
|
|
||||||
if (this.prepareConnection && session.isConnected() && isSameConnectionForEntireSession(session)) {
|
|
||||||
// We're running with connection release mode "on_close": We're able to reset
|
|
||||||
// the isolation level and/or read-only flag of the JDBC Connection here.
|
|
||||||
// Else, we need to rely on the connection pool to perform proper cleanup.
|
|
||||||
try {
|
|
||||||
Connection con = session.connection();
|
|
||||||
DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
logger.debug("Could not access JDBC Connection of Hibernate Session", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (txObject.isNewSession()) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Closing Hibernate Session [" + SessionFactoryUtils.toString(session) +
|
|
||||||
"] after transaction");
|
|
||||||
}
|
|
||||||
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Not closing pre-bound Hibernate Session [" +
|
|
||||||
SessionFactoryUtils.toString(session) + "] after transaction");
|
|
||||||
}
|
|
||||||
if (txObject.getSessionHolder().getPreviousFlushMode() != null) {
|
|
||||||
session.setFlushMode(txObject.getSessionHolder().getPreviousFlushMode());
|
|
||||||
}
|
|
||||||
if (!this.hibernateManagedSession) {
|
|
||||||
session.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
txObject.getSessionHolder().clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return whether the given Hibernate Session will always hold the same
|
|
||||||
* JDBC Connection. This is used to check whether the transaction manager
|
|
||||||
* can safely prepare and clean up the JDBC Connection used for a transaction.
|
|
||||||
* <p>Default implementation checks the Session's connection release mode
|
|
||||||
* to be "on_close". Unfortunately, this requires casting to SessionImpl,
|
|
||||||
* as of Hibernate 3.1. If that cast doesn't work, we'll simply assume
|
|
||||||
* we're safe and return {@code true}.
|
|
||||||
* @param session the Hibernate Session to check
|
|
||||||
* @see org.hibernate.impl.SessionImpl#getConnectionReleaseMode()
|
|
||||||
* @see org.hibernate.ConnectionReleaseMode#ON_CLOSE
|
|
||||||
*/
|
|
||||||
protected boolean isSameConnectionForEntireSession(Session session) {
|
|
||||||
if (!(session instanceof SessionImpl)) {
|
|
||||||
// The best we can do is to assume we're safe.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
ConnectionReleaseMode releaseMode = ((SessionImpl) session).getConnectionReleaseMode();
|
|
||||||
return ConnectionReleaseMode.ON_CLOSE.equals(releaseMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the given HibernateException to an appropriate exception
|
|
||||||
* from the {@code org.springframework.dao} hierarchy.
|
|
||||||
* <p>Will automatically apply a specified SQLExceptionTranslator to a
|
|
||||||
* Hibernate JDBCException, else rely on Hibernate's default translation.
|
|
||||||
* @param ex HibernateException that occurred
|
|
||||||
* @return a corresponding DataAccessException
|
|
||||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
|
||||||
* @see #setJdbcExceptionTranslator
|
|
||||||
*/
|
|
||||||
protected DataAccessException convertHibernateAccessException(HibernateException ex) {
|
|
||||||
if (getJdbcExceptionTranslator() != null && ex instanceof JDBCException) {
|
|
||||||
return convertJdbcAccessException((JDBCException) ex, getJdbcExceptionTranslator());
|
|
||||||
}
|
|
||||||
else if (GenericJDBCException.class == ex.getClass()) {
|
|
||||||
return convertJdbcAccessException((GenericJDBCException) ex, getDefaultJdbcExceptionTranslator());
|
|
||||||
}
|
|
||||||
return SessionFactoryUtils.convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the given Hibernate JDBCException to an appropriate exception
|
|
||||||
* from the {@code org.springframework.dao} hierarchy, using the
|
|
||||||
* given SQLExceptionTranslator.
|
|
||||||
* @param ex Hibernate JDBCException that occurred
|
|
||||||
* @param translator the SQLExceptionTranslator to use
|
|
||||||
* @return a corresponding DataAccessException
|
|
||||||
*/
|
|
||||||
protected DataAccessException convertJdbcAccessException(JDBCException ex, SQLExceptionTranslator translator) {
|
|
||||||
return translator.translate("Hibernate flushing: " + ex.getMessage(), ex.getSQL(), ex.getSQLException());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain a default SQLExceptionTranslator, lazily creating it if necessary.
|
|
||||||
* <p>Creates a default
|
|
||||||
* {@link org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator}
|
|
||||||
* for the SessionFactory's underlying DataSource.
|
|
||||||
*/
|
|
||||||
protected synchronized SQLExceptionTranslator getDefaultJdbcExceptionTranslator() {
|
|
||||||
if (this.defaultJdbcExceptionTranslator == null) {
|
|
||||||
if (getDataSource() != null) {
|
|
||||||
this.defaultJdbcExceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(getDataSource());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.defaultJdbcExceptionTranslator = SessionFactoryUtils.newJdbcExceptionTranslator(getSessionFactory());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.defaultJdbcExceptionTranslator;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate transaction object, representing a SessionHolder.
|
|
||||||
* Used as transaction object by HibernateTransactionManager.
|
|
||||||
*/
|
|
||||||
private class HibernateTransactionObject extends JdbcTransactionObjectSupport {
|
|
||||||
|
|
||||||
private SessionHolder sessionHolder;
|
|
||||||
|
|
||||||
private boolean newSessionHolder;
|
|
||||||
|
|
||||||
private boolean newSession;
|
|
||||||
|
|
||||||
public void setSession(Session session) {
|
|
||||||
this.sessionHolder = new SessionHolder(session);
|
|
||||||
this.newSessionHolder = true;
|
|
||||||
this.newSession = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExistingSession(Session session) {
|
|
||||||
this.sessionHolder = new SessionHolder(session);
|
|
||||||
this.newSessionHolder = true;
|
|
||||||
this.newSession = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSessionHolder(SessionHolder sessionHolder) {
|
|
||||||
this.sessionHolder = sessionHolder;
|
|
||||||
this.newSessionHolder = false;
|
|
||||||
this.newSession = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SessionHolder getSessionHolder() {
|
|
||||||
return this.sessionHolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNewSessionHolder() {
|
|
||||||
return this.newSessionHolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNewSession() {
|
|
||||||
return this.newSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasSpringManagedTransaction() {
|
|
||||||
return (this.sessionHolder != null && this.sessionHolder.getTransaction() != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasHibernateManagedTransaction() {
|
|
||||||
return (this.sessionHolder != null && this.sessionHolder.getSession().getTransaction().isActive());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRollbackOnly() {
|
|
||||||
this.sessionHolder.setRollbackOnly();
|
|
||||||
if (hasConnectionHolder()) {
|
|
||||||
getConnectionHolder().setRollbackOnly();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRollbackOnly() {
|
|
||||||
return this.sessionHolder.isRollbackOnly() ||
|
|
||||||
(hasConnectionHolder() && getConnectionHolder().isRollbackOnly());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void flush() {
|
|
||||||
try {
|
|
||||||
this.sessionHolder.getSession().flush();
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
throw convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holder for suspended resources.
|
|
||||||
* Used internally by {@code doSuspend} and {@code doResume}.
|
|
||||||
*/
|
|
||||||
private static class SuspendedResourcesHolder {
|
|
||||||
|
|
||||||
private final SessionHolder sessionHolder;
|
|
||||||
|
|
||||||
private final ConnectionHolder connectionHolder;
|
|
||||||
|
|
||||||
private SuspendedResourcesHolder(SessionHolder sessionHolder, ConnectionHolder conHolder) {
|
|
||||||
this.sessionHolder = sessionHolder;
|
|
||||||
this.connectionHolder = conHolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
private SessionHolder getSessionHolder() {
|
|
||||||
return this.sessionHolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ConnectionHolder getConnectionHolder() {
|
|
||||||
return this.connectionHolder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,128 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.Properties;
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.connection.ConnectionProvider;
|
|
||||||
import org.hibernate.util.JDBCExceptionReporter;
|
|
||||||
|
|
||||||
import org.springframework.jdbc.datasource.DataSourceUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate connection provider for local DataSource instances
|
|
||||||
* in an application context. This provider will be used if
|
|
||||||
* LocalSessionFactoryBean's "dataSource" property is set
|
|
||||||
* without a Hibernate TransactionManagerLookup.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see LocalSessionFactoryBean#setDataSource
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class LocalDataSourceConnectionProvider implements ConnectionProvider {
|
|
||||||
|
|
||||||
private DataSource dataSource;
|
|
||||||
|
|
||||||
private DataSource dataSourceToUse;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void configure(Properties props) throws HibernateException {
|
|
||||||
this.dataSource = LocalSessionFactoryBean.getConfigTimeDataSource();
|
|
||||||
// absolutely needs thread-bound DataSource to initialize
|
|
||||||
if (this.dataSource == null) {
|
|
||||||
throw new HibernateException("No local DataSource found for configuration - " +
|
|
||||||
"'dataSource' property must be set on LocalSessionFactoryBean");
|
|
||||||
}
|
|
||||||
this.dataSourceToUse = getDataSourceToUse(this.dataSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the DataSource to use for retrieving Connections.
|
|
||||||
* <p>This implementation returns the passed-in DataSource as-is.
|
|
||||||
* @param originalDataSource the DataSource as configured by the user
|
|
||||||
* on LocalSessionFactoryBean
|
|
||||||
* @return the DataSource to actually retrieve Connections from
|
|
||||||
* (potentially wrapped)
|
|
||||||
* @see LocalSessionFactoryBean#setDataSource
|
|
||||||
*/
|
|
||||||
protected DataSource getDataSourceToUse(DataSource originalDataSource) {
|
|
||||||
return originalDataSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the DataSource that this ConnectionProvider wraps.
|
|
||||||
*/
|
|
||||||
public DataSource getDataSource() {
|
|
||||||
return this.dataSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation delegates to the underlying DataSource.
|
|
||||||
* @see javax.sql.DataSource#getConnection()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Connection getConnection() throws SQLException {
|
|
||||||
try {
|
|
||||||
return this.dataSourceToUse.getConnection();
|
|
||||||
}
|
|
||||||
catch (SQLException ex) {
|
|
||||||
JDBCExceptionReporter.logExceptions(ex);
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation calls {@link DataSourceUtils#doCloseConnection},
|
|
||||||
* checking against a {@link org.springframework.jdbc.datasource.SmartDataSource}.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void closeConnection(Connection con) throws SQLException {
|
|
||||||
try {
|
|
||||||
DataSourceUtils.doCloseConnection(con, this.dataSourceToUse);
|
|
||||||
}
|
|
||||||
catch (SQLException ex) {
|
|
||||||
JDBCExceptionReporter.logExceptions(ex);
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation does nothing:
|
|
||||||
* We're dealing with an externally managed DataSource.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation returns {@code false}: We cannot guarantee
|
|
||||||
* to receive the same Connection within a transaction, not even when
|
|
||||||
* dealing with a JNDI DataSource.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean supportsAggressiveRelease() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subclass of LocalDataSourceConnectionProvider that will be used
|
|
||||||
* if LocalSessionFactoryBean's "dataSource" property is set
|
|
||||||
* in combination with a Hibernate TransactionManagerLookup.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 2.5.1
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class LocalJtaDataSourceConnectionProvider extends LocalDataSourceConnectionProvider {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation returns {@code true},
|
|
||||||
* since we're assuming a JTA DataSource.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean supportsAggressiveRelease() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,122 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2013 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
import org.hibernate.cache.CacheDataDescription;
|
|
||||||
import org.hibernate.cache.CacheException;
|
|
||||||
import org.hibernate.cache.CollectionRegion;
|
|
||||||
import org.hibernate.cache.EntityRegion;
|
|
||||||
import org.hibernate.cache.QueryResultsRegion;
|
|
||||||
import org.hibernate.cache.RegionFactory;
|
|
||||||
import org.hibernate.cache.TimestampsRegion;
|
|
||||||
import org.hibernate.cache.access.AccessType;
|
|
||||||
import org.hibernate.cfg.Settings;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Proxy for a Hibernate RegionFactory, delegating to a Spring-managed
|
|
||||||
* RegionFactory instance, determined by LocalSessionFactoryBean's
|
|
||||||
* "cacheRegionFactory" property.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.0
|
|
||||||
* @see LocalSessionFactoryBean#setCacheRegionFactory
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class LocalRegionFactoryProxy implements RegionFactory {
|
|
||||||
|
|
||||||
private final RegionFactory regionFactory;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Standard constructor.
|
|
||||||
*/
|
|
||||||
public LocalRegionFactoryProxy() {
|
|
||||||
RegionFactory rf = (RegionFactory) LocalSessionFactoryBean.getConfigTimeRegionFactory();
|
|
||||||
// absolutely needs thread-bound RegionFactory to initialize
|
|
||||||
if (rf == null) {
|
|
||||||
throw new IllegalStateException("No Hibernate RegionFactory found - " +
|
|
||||||
"'cacheRegionFactory' property must be set on LocalSessionFactoryBean");
|
|
||||||
}
|
|
||||||
this.regionFactory = rf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Properties constructor: not used by this class or formally required,
|
|
||||||
* but enforced by Hibernate when reflectively instantiating a RegionFactory.
|
|
||||||
*/
|
|
||||||
public LocalRegionFactoryProxy(Properties properties) {
|
|
||||||
this();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void start(Settings settings, Properties properties) throws CacheException {
|
|
||||||
this.regionFactory.start(settings, properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stop() {
|
|
||||||
this.regionFactory.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isMinimalPutsEnabledByDefault() {
|
|
||||||
return this.regionFactory.isMinimalPutsEnabledByDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessType getDefaultAccessType() {
|
|
||||||
return this.regionFactory.getDefaultAccessType();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long nextTimestamp() {
|
|
||||||
return this.regionFactory.nextTimestamp();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata)
|
|
||||||
throws CacheException {
|
|
||||||
|
|
||||||
return this.regionFactory.buildEntityRegion(regionName, properties, metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CollectionRegion buildCollectionRegion(String regionName, Properties properties,
|
|
||||||
CacheDataDescription metadata) throws CacheException {
|
|
||||||
|
|
||||||
return this.regionFactory.buildCollectionRegion(regionName, properties, metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties)
|
|
||||||
throws CacheException {
|
|
||||||
|
|
||||||
return this.regionFactory.buildQueryResultsRegion(regionName, properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties)
|
|
||||||
throws CacheException {
|
|
||||||
|
|
||||||
return this.regionFactory.buildTimestampsRegion(regionName, properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,77 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import java.util.Properties;
|
|
||||||
import javax.transaction.Transaction;
|
|
||||||
import javax.transaction.TransactionManager;
|
|
||||||
|
|
||||||
import org.hibernate.transaction.TransactionManagerLookup;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of Hibernate's {@link TransactionManagerLookup} interface
|
|
||||||
* that returns a Spring-managed JTA {@link TransactionManager}, determined
|
|
||||||
* by LocalSessionFactoryBean's "jtaTransactionManager" property.
|
|
||||||
*
|
|
||||||
* <p>The main advantage of this TransactionManagerLookup is that it avoids
|
|
||||||
* double configuration of JTA specifics. A single TransactionManager bean can
|
|
||||||
* be used for both JtaTransactionManager and LocalSessionFactoryBean, with no
|
|
||||||
* JTA setup in Hibernate configuration.
|
|
||||||
*
|
|
||||||
* <p>Alternatively, use Hibernate's own TransactionManagerLookup implementations:
|
|
||||||
* Spring's JtaTransactionManager only requires a TransactionManager for suspending
|
|
||||||
* and resuming transactions, so you might not need to apply such special Spring
|
|
||||||
* configuration at all.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see LocalSessionFactoryBean#setJtaTransactionManager
|
|
||||||
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class LocalTransactionManagerLookup implements TransactionManagerLookup {
|
|
||||||
|
|
||||||
private final TransactionManager transactionManager;
|
|
||||||
|
|
||||||
|
|
||||||
public LocalTransactionManagerLookup() {
|
|
||||||
TransactionManager tm = LocalSessionFactoryBean.getConfigTimeTransactionManager();
|
|
||||||
// absolutely needs thread-bound TransactionManager to initialize
|
|
||||||
if (tm == null) {
|
|
||||||
throw new IllegalStateException("No JTA TransactionManager found - " +
|
|
||||||
"'jtaTransactionManager' property must be set on LocalSessionFactoryBean");
|
|
||||||
}
|
|
||||||
this.transactionManager = tm;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TransactionManager getTransactionManager(Properties props) {
|
|
||||||
return this.transactionManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUserTransactionName() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getTransactionIdentifier(Transaction transaction) {
|
|
||||||
return transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,832 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
import javax.transaction.Status;
|
|
||||||
import javax.transaction.Transaction;
|
|
||||||
import javax.transaction.TransactionManager;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.hibernate.Criteria;
|
|
||||||
import org.hibernate.FlushMode;
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.Interceptor;
|
|
||||||
import org.hibernate.JDBCException;
|
|
||||||
import org.hibernate.NonUniqueObjectException;
|
|
||||||
import org.hibernate.NonUniqueResultException;
|
|
||||||
import org.hibernate.ObjectDeletedException;
|
|
||||||
import org.hibernate.OptimisticLockException;
|
|
||||||
import org.hibernate.PersistentObjectException;
|
|
||||||
import org.hibernate.PessimisticLockException;
|
|
||||||
import org.hibernate.PropertyValueException;
|
|
||||||
import org.hibernate.Query;
|
|
||||||
import org.hibernate.QueryException;
|
|
||||||
import org.hibernate.QueryTimeoutException;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
import org.hibernate.StaleObjectStateException;
|
|
||||||
import org.hibernate.StaleStateException;
|
|
||||||
import org.hibernate.TransientObjectException;
|
|
||||||
import org.hibernate.UnresolvableObjectException;
|
|
||||||
import org.hibernate.WrongClassException;
|
|
||||||
import org.hibernate.connection.ConnectionProvider;
|
|
||||||
import org.hibernate.engine.SessionFactoryImplementor;
|
|
||||||
import org.hibernate.exception.ConstraintViolationException;
|
|
||||||
import org.hibernate.exception.DataException;
|
|
||||||
import org.hibernate.exception.JDBCConnectionException;
|
|
||||||
import org.hibernate.exception.LockAcquisitionException;
|
|
||||||
import org.hibernate.exception.SQLGrammarException;
|
|
||||||
|
|
||||||
import org.springframework.core.NamedThreadLocal;
|
|
||||||
import org.springframework.dao.CannotAcquireLockException;
|
|
||||||
import org.springframework.dao.DataAccessException;
|
|
||||||
import org.springframework.dao.DataAccessResourceFailureException;
|
|
||||||
import org.springframework.dao.DataIntegrityViolationException;
|
|
||||||
import org.springframework.dao.DuplicateKeyException;
|
|
||||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
|
||||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
|
||||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
|
||||||
import org.springframework.dao.PessimisticLockingFailureException;
|
|
||||||
import org.springframework.jdbc.datasource.DataSourceUtils;
|
|
||||||
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
|
|
||||||
import org.springframework.jdbc.support.SQLExceptionTranslator;
|
|
||||||
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
|
|
||||||
import org.springframework.transaction.jta.SpringJtaSynchronizationAdapter;
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class featuring methods for Hibernate Session handling,
|
|
||||||
* allowing for reuse of Hibernate Session instances within transactions.
|
|
||||||
* Also provides support for exception translation.
|
|
||||||
*
|
|
||||||
* <p>Supports synchronization with both Spring-managed JTA transactions
|
|
||||||
* (see {@link org.springframework.transaction.jta.JtaTransactionManager})
|
|
||||||
* and non-Spring JTA transactions (i.e. plain JTA or EJB CMT),
|
|
||||||
* transparently providing transaction-scoped Hibernate Sessions.
|
|
||||||
* Note that for non-Spring JTA transactions, a JTA TransactionManagerLookup
|
|
||||||
* has to be specified in the Hibernate configuration.
|
|
||||||
*
|
|
||||||
* <p>Used internally by {@link HibernateTemplate}, {@link HibernateInterceptor}
|
|
||||||
* and {@link HibernateTransactionManager}. Can also be used directly in
|
|
||||||
* application code.
|
|
||||||
*
|
|
||||||
* <p>Requires Hibernate 3.6.x, as of Spring 4.0.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see #getSession
|
|
||||||
* @see #releaseSession
|
|
||||||
* @see HibernateTransactionManager
|
|
||||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
|
||||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public abstract class SessionFactoryUtils {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Order value for TransactionSynchronization objects that clean up Hibernate Sessions.
|
|
||||||
* Returns {@code DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100}
|
|
||||||
* to execute Session cleanup before JDBC Connection cleanup, if any.
|
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#CONNECTION_SYNCHRONIZATION_ORDER
|
|
||||||
*/
|
|
||||||
public static final int SESSION_SYNCHRONIZATION_ORDER =
|
|
||||||
DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100;
|
|
||||||
|
|
||||||
static final Log logger = LogFactory.getLog(SessionFactoryUtils.class);
|
|
||||||
|
|
||||||
private static final ThreadLocal<Map<SessionFactory, Set<Session>>> deferredCloseHolder =
|
|
||||||
new NamedThreadLocal<Map<SessionFactory, Set<Session>>>("Hibernate Sessions registered for deferred close");
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine the DataSource of the given SessionFactory.
|
|
||||||
* @param sessionFactory the SessionFactory to check
|
|
||||||
* @return the DataSource, or {@code null} if none found
|
|
||||||
* @see org.hibernate.engine.SessionFactoryImplementor#getConnectionProvider
|
|
||||||
* @see LocalDataSourceConnectionProvider
|
|
||||||
*/
|
|
||||||
public static DataSource getDataSource(SessionFactory sessionFactory) {
|
|
||||||
if (sessionFactory instanceof SessionFactoryImplementor) {
|
|
||||||
ConnectionProvider cp = ((SessionFactoryImplementor) sessionFactory).getConnectionProvider();
|
|
||||||
if (cp instanceof LocalDataSourceConnectionProvider) {
|
|
||||||
return ((LocalDataSourceConnectionProvider) cp).getDataSource();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an appropriate SQLExceptionTranslator for the given SessionFactory.
|
|
||||||
* If a DataSource is found, a SQLErrorCodeSQLExceptionTranslator for the DataSource
|
|
||||||
* is created; else, a SQLStateSQLExceptionTranslator as fallback.
|
|
||||||
* @param sessionFactory the SessionFactory to create the translator for
|
|
||||||
* @return the SQLExceptionTranslator
|
|
||||||
* @see #getDataSource
|
|
||||||
* @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
|
|
||||||
* @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
|
|
||||||
*/
|
|
||||||
public static SQLExceptionTranslator newJdbcExceptionTranslator(SessionFactory sessionFactory) {
|
|
||||||
DataSource ds = getDataSource(sessionFactory);
|
|
||||||
if (ds != null) {
|
|
||||||
return new SQLErrorCodeSQLExceptionTranslator(ds);
|
|
||||||
}
|
|
||||||
return new SQLStateSQLExceptionTranslator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Try to retrieve the JTA TransactionManager from the given SessionFactory
|
|
||||||
* and/or Session. Check the passed-in SessionFactory for implementing
|
|
||||||
* SessionFactoryImplementor (the usual case), falling back to the
|
|
||||||
* SessionFactory reference that the Session itself carries.
|
|
||||||
* @param sessionFactory Hibernate SessionFactory
|
|
||||||
* @param session Hibernate Session (can also be {@code null})
|
|
||||||
* @return the JTA TransactionManager, if any
|
|
||||||
* @see javax.transaction.TransactionManager
|
|
||||||
* @see SessionFactoryImplementor#getTransactionManager
|
|
||||||
* @see Session#getSessionFactory
|
|
||||||
* @see org.hibernate.impl.SessionFactoryImpl
|
|
||||||
*/
|
|
||||||
public static TransactionManager getJtaTransactionManager(SessionFactory sessionFactory, Session session) {
|
|
||||||
SessionFactoryImplementor sessionFactoryImpl = null;
|
|
||||||
if (sessionFactory instanceof SessionFactoryImplementor) {
|
|
||||||
sessionFactoryImpl = ((SessionFactoryImplementor) sessionFactory);
|
|
||||||
}
|
|
||||||
else if (session != null) {
|
|
||||||
SessionFactory internalFactory = session.getSessionFactory();
|
|
||||||
if (internalFactory instanceof SessionFactoryImplementor) {
|
|
||||||
sessionFactoryImpl = (SessionFactoryImplementor) internalFactory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (sessionFactoryImpl != null ? sessionFactoryImpl.getTransactionManager() : null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a Hibernate Session for the given SessionFactory. Is aware of and will
|
|
||||||
* return any existing corresponding Session bound to the current thread, for
|
|
||||||
* example when using {@link HibernateTransactionManager}. Will create a new
|
|
||||||
* Session otherwise, if "allowCreate" is {@code true}.
|
|
||||||
* <p>This is the {@code getSession} method used by typical data access code,
|
|
||||||
* in combination with {@code releaseSession} called when done with
|
|
||||||
* the Session. Note that HibernateTemplate allows to write data access code
|
|
||||||
* without caring about such resource handling.
|
|
||||||
* @param sessionFactory Hibernate SessionFactory to create the session with
|
|
||||||
* @param allowCreate whether a non-transactional Session should be created
|
|
||||||
* when no transactional Session can be found for the current thread
|
|
||||||
* @return the Hibernate Session
|
|
||||||
* @throws DataAccessResourceFailureException if the Session couldn't be created
|
|
||||||
* @throws IllegalStateException if no thread-bound Session found and
|
|
||||||
* "allowCreate" is {@code false}
|
|
||||||
* @see #getSession(SessionFactory, Interceptor, SQLExceptionTranslator)
|
|
||||||
* @see #releaseSession
|
|
||||||
* @see HibernateTemplate
|
|
||||||
*/
|
|
||||||
public static Session getSession(SessionFactory sessionFactory, boolean allowCreate)
|
|
||||||
throws DataAccessResourceFailureException, IllegalStateException {
|
|
||||||
|
|
||||||
try {
|
|
||||||
return doGetSession(sessionFactory, null, null, allowCreate);
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a Hibernate Session for the given SessionFactory. Is aware of and will
|
|
||||||
* return any existing corresponding Session bound to the current thread, for
|
|
||||||
* example when using {@link HibernateTransactionManager}. Will always create
|
|
||||||
* a new Session otherwise.
|
|
||||||
* <p>Supports setting a Session-level Hibernate entity interceptor that allows
|
|
||||||
* to inspect and change property values before writing to and reading from the
|
|
||||||
* database. Such an interceptor can also be set at the SessionFactory level
|
|
||||||
* (i.e. on LocalSessionFactoryBean), on HibernateTransactionManager, etc.
|
|
||||||
* @param sessionFactory Hibernate SessionFactory to create the session with
|
|
||||||
* @param entityInterceptor Hibernate entity interceptor, or {@code null} if none
|
|
||||||
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
|
|
||||||
* Session on transaction synchronization (may be {@code null}; only used
|
|
||||||
* when actually registering a transaction synchronization)
|
|
||||||
* @return the Hibernate Session
|
|
||||||
* @throws DataAccessResourceFailureException if the Session couldn't be created
|
|
||||||
* @see LocalSessionFactoryBean#setEntityInterceptor
|
|
||||||
* @see HibernateTemplate#setEntityInterceptor
|
|
||||||
*/
|
|
||||||
public static Session getSession(
|
|
||||||
SessionFactory sessionFactory, Interceptor entityInterceptor,
|
|
||||||
SQLExceptionTranslator jdbcExceptionTranslator) throws DataAccessResourceFailureException {
|
|
||||||
|
|
||||||
try {
|
|
||||||
return doGetSession(sessionFactory, entityInterceptor, jdbcExceptionTranslator, true);
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a Hibernate Session for the given SessionFactory. Is aware of and will
|
|
||||||
* return any existing corresponding Session bound to the current thread, for
|
|
||||||
* example when using {@link HibernateTransactionManager}. Will create a new
|
|
||||||
* Session otherwise, if "allowCreate" is {@code true}.
|
|
||||||
* <p>Throws the original HibernateException, in contrast to {@link #getSession}.
|
|
||||||
* @param sessionFactory Hibernate SessionFactory to create the session with
|
|
||||||
* @param allowCreate whether a non-transactional Session should be created
|
|
||||||
* when no transactional Session can be found for the current thread
|
|
||||||
* @return the Hibernate Session
|
|
||||||
* @throws HibernateException if the Session couldn't be created
|
|
||||||
* @throws IllegalStateException if no thread-bound Session found and allowCreate false
|
|
||||||
*/
|
|
||||||
public static Session doGetSession(SessionFactory sessionFactory, boolean allowCreate)
|
|
||||||
throws HibernateException, IllegalStateException {
|
|
||||||
|
|
||||||
return doGetSession(sessionFactory, null, null, allowCreate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a Hibernate Session for the given SessionFactory. Is aware of and will
|
|
||||||
* return any existing corresponding Session bound to the current thread, for
|
|
||||||
* example when using {@link HibernateTransactionManager}. Will create a new
|
|
||||||
* Session otherwise, if "allowCreate" is {@code true}.
|
|
||||||
* <p>Same as {@link #getSession}, but throwing the original HibernateException.
|
|
||||||
* @param sessionFactory Hibernate SessionFactory to create the session with
|
|
||||||
* @param entityInterceptor Hibernate entity interceptor, or {@code null} if none
|
|
||||||
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
|
|
||||||
* Session on transaction synchronization (may be {@code null})
|
|
||||||
* @param allowCreate whether a non-transactional Session should be created
|
|
||||||
* when no transactional Session can be found for the current thread
|
|
||||||
* @return the Hibernate Session
|
|
||||||
* @throws HibernateException if the Session couldn't be created
|
|
||||||
* @throws IllegalStateException if no thread-bound Session found and
|
|
||||||
* "allowCreate" is {@code false}
|
|
||||||
*/
|
|
||||||
private static Session doGetSession(
|
|
||||||
SessionFactory sessionFactory, Interceptor entityInterceptor,
|
|
||||||
SQLExceptionTranslator jdbcExceptionTranslator, boolean allowCreate)
|
|
||||||
throws HibernateException, IllegalStateException {
|
|
||||||
|
|
||||||
Assert.notNull(sessionFactory, "No SessionFactory specified");
|
|
||||||
|
|
||||||
Object resource = TransactionSynchronizationManager.getResource(sessionFactory);
|
|
||||||
if (resource instanceof Session) {
|
|
||||||
return (Session) resource;
|
|
||||||
}
|
|
||||||
SessionHolder sessionHolder = (SessionHolder) resource;
|
|
||||||
if (sessionHolder != null && !sessionHolder.isEmpty()) {
|
|
||||||
// pre-bound Hibernate Session
|
|
||||||
Session session = null;
|
|
||||||
if (TransactionSynchronizationManager.isSynchronizationActive() &&
|
|
||||||
sessionHolder.doesNotHoldNonDefaultSession()) {
|
|
||||||
// Spring transaction management is active ->
|
|
||||||
// register pre-bound Session with it for transactional flushing.
|
|
||||||
session = sessionHolder.getValidatedSession();
|
|
||||||
if (session != null && !sessionHolder.isSynchronizedWithTransaction()) {
|
|
||||||
logger.debug("Registering Spring transaction synchronization for existing Hibernate Session");
|
|
||||||
TransactionSynchronizationManager.registerSynchronization(
|
|
||||||
new SpringSessionSynchronization(sessionHolder, sessionFactory, jdbcExceptionTranslator, false));
|
|
||||||
sessionHolder.setSynchronizedWithTransaction(true);
|
|
||||||
// Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
|
|
||||||
// with FlushMode.MANUAL, which needs to allow flushing within the transaction.
|
|
||||||
FlushMode flushMode = session.getFlushMode();
|
|
||||||
if (flushMode.lessThan(FlushMode.COMMIT) &&
|
|
||||||
!TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
|
|
||||||
session.setFlushMode(FlushMode.AUTO);
|
|
||||||
sessionHolder.setPreviousFlushMode(flushMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// No Spring transaction management active -> try JTA transaction synchronization.
|
|
||||||
session = getJtaSynchronizedSession(sessionHolder, sessionFactory, jdbcExceptionTranslator);
|
|
||||||
}
|
|
||||||
if (session != null) {
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug("Opening Hibernate Session");
|
|
||||||
Session session = (entityInterceptor != null ?
|
|
||||||
sessionFactory.openSession(entityInterceptor) : sessionFactory.openSession());
|
|
||||||
|
|
||||||
// Use same Session for further Hibernate actions within the transaction.
|
|
||||||
// Thread object will get removed by synchronization at transaction completion.
|
|
||||||
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
|
||||||
// We're within a Spring-managed transaction, possibly from JtaTransactionManager.
|
|
||||||
logger.debug("Registering Spring transaction synchronization for new Hibernate Session");
|
|
||||||
SessionHolder holderToUse = sessionHolder;
|
|
||||||
if (holderToUse == null) {
|
|
||||||
holderToUse = new SessionHolder(session);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
holderToUse.addSession(session);
|
|
||||||
}
|
|
||||||
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
|
||||||
}
|
|
||||||
TransactionSynchronizationManager.registerSynchronization(
|
|
||||||
new SpringSessionSynchronization(holderToUse, sessionFactory, jdbcExceptionTranslator, true));
|
|
||||||
holderToUse.setSynchronizedWithTransaction(true);
|
|
||||||
if (holderToUse != sessionHolder) {
|
|
||||||
TransactionSynchronizationManager.bindResource(sessionFactory, holderToUse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// No Spring transaction management active -> try JTA transaction synchronization.
|
|
||||||
registerJtaSynchronization(session, sessionFactory, jdbcExceptionTranslator, sessionHolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check whether we are allowed to return the Session.
|
|
||||||
if (!allowCreate && !isSessionTransactional(session, sessionFactory)) {
|
|
||||||
closeSession(session);
|
|
||||||
throw new IllegalStateException("No Hibernate Session bound to thread, " +
|
|
||||||
"and configuration does not allow creation of non-transactional one here");
|
|
||||||
}
|
|
||||||
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve a Session from the given SessionHolder, potentially from a
|
|
||||||
* JTA transaction synchronization.
|
|
||||||
* @param sessionHolder the SessionHolder to check
|
|
||||||
* @param sessionFactory the SessionFactory to get the JTA TransactionManager from
|
|
||||||
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
|
|
||||||
* Session on transaction synchronization (may be {@code null})
|
|
||||||
* @return the associated Session, if any
|
|
||||||
* @throws DataAccessResourceFailureException if the Session couldn't be created
|
|
||||||
*/
|
|
||||||
private static Session getJtaSynchronizedSession(
|
|
||||||
SessionHolder sessionHolder, SessionFactory sessionFactory,
|
|
||||||
SQLExceptionTranslator jdbcExceptionTranslator) throws DataAccessResourceFailureException {
|
|
||||||
|
|
||||||
// JTA synchronization is only possible with a javax.transaction.TransactionManager.
|
|
||||||
// We'll check the Hibernate SessionFactory: If a TransactionManagerLookup is specified
|
|
||||||
// in Hibernate configuration, it will contain a TransactionManager reference.
|
|
||||||
TransactionManager jtaTm = getJtaTransactionManager(sessionFactory, sessionHolder.getAnySession());
|
|
||||||
if (jtaTm != null) {
|
|
||||||
// Check whether JTA transaction management is active ->
|
|
||||||
// fetch pre-bound Session for the current JTA transaction, if any.
|
|
||||||
// (just necessary for JTA transaction suspension, with an individual
|
|
||||||
// Hibernate Session per currently active/suspended transaction)
|
|
||||||
try {
|
|
||||||
// Look for transaction-specific Session.
|
|
||||||
Transaction jtaTx = jtaTm.getTransaction();
|
|
||||||
if (jtaTx != null) {
|
|
||||||
int jtaStatus = jtaTx.getStatus();
|
|
||||||
if (jtaStatus == Status.STATUS_ACTIVE || jtaStatus == Status.STATUS_MARKED_ROLLBACK) {
|
|
||||||
Session session = sessionHolder.getValidatedSession(jtaTx);
|
|
||||||
if (session == null && !sessionHolder.isSynchronizedWithTransaction()) {
|
|
||||||
// No transaction-specific Session found: If not already marked as
|
|
||||||
// synchronized with transaction, register the default thread-bound
|
|
||||||
// Session as JTA-transactional. If there is no default Session,
|
|
||||||
// we're a new inner JTA transaction with an outer one being suspended:
|
|
||||||
// In that case, we'll return null to trigger opening of a new Session.
|
|
||||||
session = sessionHolder.getValidatedSession();
|
|
||||||
if (session != null) {
|
|
||||||
logger.debug("Registering JTA transaction synchronization for existing Hibernate Session");
|
|
||||||
sessionHolder.addSession(jtaTx, session);
|
|
||||||
jtaTx.registerSynchronization(
|
|
||||||
new SpringJtaSynchronizationAdapter(
|
|
||||||
new SpringSessionSynchronization(sessionHolder, sessionFactory, jdbcExceptionTranslator, false),
|
|
||||||
jtaTm));
|
|
||||||
sessionHolder.setSynchronizedWithTransaction(true);
|
|
||||||
// Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
|
|
||||||
// with FlushMode.NEVER, which needs to allow flushing within the transaction.
|
|
||||||
FlushMode flushMode = session.getFlushMode();
|
|
||||||
if (flushMode.lessThan(FlushMode.COMMIT)) {
|
|
||||||
session.setFlushMode(FlushMode.AUTO);
|
|
||||||
sessionHolder.setPreviousFlushMode(flushMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// No transaction active -> simply return default thread-bound Session, if any
|
|
||||||
// (possibly from OpenSessionInViewFilter/Interceptor).
|
|
||||||
return sessionHolder.getValidatedSession();
|
|
||||||
}
|
|
||||||
catch (Throwable ex) {
|
|
||||||
throw new DataAccessResourceFailureException("Could not check JTA transaction", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// No JTA TransactionManager -> simply return default thread-bound Session, if any
|
|
||||||
// (possibly from OpenSessionInViewFilter/Interceptor).
|
|
||||||
return sessionHolder.getValidatedSession();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a JTA synchronization for the given Session, if any.
|
|
||||||
* @param sessionHolder the existing thread-bound SessionHolder, if any
|
|
||||||
* @param session the Session to register
|
|
||||||
* @param sessionFactory the SessionFactory that the Session was created with
|
|
||||||
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
|
|
||||||
* Session on transaction synchronization (may be {@code null})
|
|
||||||
*/
|
|
||||||
private static void registerJtaSynchronization(Session session, SessionFactory sessionFactory,
|
|
||||||
SQLExceptionTranslator jdbcExceptionTranslator, SessionHolder sessionHolder) {
|
|
||||||
|
|
||||||
// JTA synchronization is only possible with a javax.transaction.TransactionManager.
|
|
||||||
// We'll check the Hibernate SessionFactory: If a TransactionManagerLookup is specified
|
|
||||||
// in Hibernate configuration, it will contain a TransactionManager reference.
|
|
||||||
TransactionManager jtaTm = getJtaTransactionManager(sessionFactory, session);
|
|
||||||
if (jtaTm != null) {
|
|
||||||
try {
|
|
||||||
Transaction jtaTx = jtaTm.getTransaction();
|
|
||||||
if (jtaTx != null) {
|
|
||||||
int jtaStatus = jtaTx.getStatus();
|
|
||||||
if (jtaStatus == Status.STATUS_ACTIVE || jtaStatus == Status.STATUS_MARKED_ROLLBACK) {
|
|
||||||
logger.debug("Registering JTA transaction synchronization for new Hibernate Session");
|
|
||||||
SessionHolder holderToUse = sessionHolder;
|
|
||||||
// Register JTA Transaction with existing SessionHolder.
|
|
||||||
// Create a new SessionHolder if none existed before.
|
|
||||||
if (holderToUse == null) {
|
|
||||||
holderToUse = new SessionHolder(jtaTx, session);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
holderToUse.addSession(jtaTx, session);
|
|
||||||
}
|
|
||||||
jtaTx.registerSynchronization(
|
|
||||||
new SpringJtaSynchronizationAdapter(
|
|
||||||
new SpringSessionSynchronization(holderToUse, sessionFactory, jdbcExceptionTranslator, true),
|
|
||||||
jtaTm));
|
|
||||||
holderToUse.setSynchronizedWithTransaction(true);
|
|
||||||
if (holderToUse != sessionHolder) {
|
|
||||||
TransactionSynchronizationManager.bindResource(sessionFactory, holderToUse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Throwable ex) {
|
|
||||||
throw new DataAccessResourceFailureException(
|
|
||||||
"Could not register synchronization with JTA TransactionManager", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a new Hibernate Session from the given SessionFactory.
|
|
||||||
* Will return a new Session even if there already is a pre-bound
|
|
||||||
* Session for the given SessionFactory.
|
|
||||||
* <p>Within a transaction, this method will create a new Session
|
|
||||||
* that shares the transaction's JDBC Connection. More specifically,
|
|
||||||
* it will use the same JDBC Connection as the pre-bound Hibernate Session.
|
|
||||||
* @param sessionFactory Hibernate SessionFactory to create the session with
|
|
||||||
* @return the new Session
|
|
||||||
*/
|
|
||||||
public static Session getNewSession(SessionFactory sessionFactory) {
|
|
||||||
return getNewSession(sessionFactory, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a new Hibernate Session from the given SessionFactory.
|
|
||||||
* Will return a new Session even if there already is a pre-bound
|
|
||||||
* Session for the given SessionFactory.
|
|
||||||
* <p>Within a transaction, this method will create a new Session
|
|
||||||
* that shares the transaction's JDBC Connection. More specifically,
|
|
||||||
* it will use the same JDBC Connection as the pre-bound Hibernate Session.
|
|
||||||
* @param sessionFactory Hibernate SessionFactory to create the session with
|
|
||||||
* @param entityInterceptor Hibernate entity interceptor, or {@code null} if none
|
|
||||||
* @return the new Session
|
|
||||||
*/
|
|
||||||
public static Session getNewSession(SessionFactory sessionFactory, Interceptor entityInterceptor) {
|
|
||||||
Assert.notNull(sessionFactory, "No SessionFactory specified");
|
|
||||||
|
|
||||||
try {
|
|
||||||
SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
|
|
||||||
if (sessionHolder != null && !sessionHolder.isEmpty()) {
|
|
||||||
if (entityInterceptor != null) {
|
|
||||||
return sessionFactory.openSession(sessionHolder.getAnySession().connection(), entityInterceptor);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return sessionFactory.openSession(sessionHolder.getAnySession().connection());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (entityInterceptor != null) {
|
|
||||||
return sessionFactory.openSession(entityInterceptor);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return sessionFactory.openSession();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stringify the given Session for debug logging.
|
|
||||||
* Returns output equivalent to {@code Object.toString()}:
|
|
||||||
* the fully qualified class name + "@" + the identity hash code.
|
|
||||||
* <p>The sole reason why this is necessary is because Hibernate3's
|
|
||||||
* {@code Session.toString()} implementation is broken (and won't be fixed):
|
|
||||||
* it logs the toString representation of all persistent objects in the Session,
|
|
||||||
* which might lead to ConcurrentModificationExceptions if the persistent objects
|
|
||||||
* in turn refer to the Session (for example, for lazy loading).
|
|
||||||
* @param session the Hibernate Session to stringify
|
|
||||||
* @return the String representation of the given Session
|
|
||||||
*/
|
|
||||||
public static String toString(Session session) {
|
|
||||||
return session.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(session));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return whether there is a transactional Hibernate Session for the current thread,
|
|
||||||
* that is, a Session bound to the current thread by Spring's transaction facilities.
|
|
||||||
* @param sessionFactory Hibernate SessionFactory to check (may be {@code null})
|
|
||||||
* @return whether there is a transactional Session for current thread
|
|
||||||
*/
|
|
||||||
public static boolean hasTransactionalSession(SessionFactory sessionFactory) {
|
|
||||||
if (sessionFactory == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
SessionHolder sessionHolder =
|
|
||||||
(SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
|
|
||||||
return (sessionHolder != null && !sessionHolder.isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return whether the given Hibernate Session is transactional, that is,
|
|
||||||
* bound to the current thread by Spring's transaction facilities.
|
|
||||||
* @param session the Hibernate Session to check
|
|
||||||
* @param sessionFactory Hibernate SessionFactory that the Session was created with
|
|
||||||
* (may be {@code null})
|
|
||||||
* @return whether the Session is transactional
|
|
||||||
*/
|
|
||||||
public static boolean isSessionTransactional(Session session, SessionFactory sessionFactory) {
|
|
||||||
if (sessionFactory == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
SessionHolder sessionHolder =
|
|
||||||
(SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
|
|
||||||
return (sessionHolder != null && sessionHolder.containsSession(session));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply the current transaction timeout, if any, to the given
|
|
||||||
* Hibernate Query object.
|
|
||||||
* @param query the Hibernate Query object
|
|
||||||
* @param sessionFactory Hibernate SessionFactory that the Query was created for
|
|
||||||
* (may be {@code null})
|
|
||||||
* @see org.hibernate.Query#setTimeout
|
|
||||||
*/
|
|
||||||
public static void applyTransactionTimeout(Query query, SessionFactory sessionFactory) {
|
|
||||||
Assert.notNull(query, "No Query object specified");
|
|
||||||
if (sessionFactory != null) {
|
|
||||||
SessionHolder sessionHolder =
|
|
||||||
(SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
|
|
||||||
if (sessionHolder != null && sessionHolder.hasTimeout()) {
|
|
||||||
query.setTimeout(sessionHolder.getTimeToLiveInSeconds());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply the current transaction timeout, if any, to the given
|
|
||||||
* Hibernate Criteria object.
|
|
||||||
* @param criteria the Hibernate Criteria object
|
|
||||||
* @param sessionFactory Hibernate SessionFactory that the Criteria was created for
|
|
||||||
* @see org.hibernate.Criteria#setTimeout
|
|
||||||
*/
|
|
||||||
public static void applyTransactionTimeout(Criteria criteria, SessionFactory sessionFactory) {
|
|
||||||
Assert.notNull(criteria, "No Criteria object specified");
|
|
||||||
if (sessionFactory != null) {
|
|
||||||
SessionHolder sessionHolder =
|
|
||||||
(SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
|
|
||||||
if (sessionHolder != null && sessionHolder.hasTimeout()) {
|
|
||||||
criteria.setTimeout(sessionHolder.getTimeToLiveInSeconds());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the given HibernateException to an appropriate exception
|
|
||||||
* from the {@code org.springframework.dao} hierarchy.
|
|
||||||
* @param ex HibernateException that occurred
|
|
||||||
* @return the corresponding DataAccessException instance
|
|
||||||
* @see HibernateAccessor#convertHibernateAccessException
|
|
||||||
* @see HibernateTransactionManager#convertHibernateAccessException
|
|
||||||
*/
|
|
||||||
public static DataAccessException convertHibernateAccessException(HibernateException ex) {
|
|
||||||
if (ex instanceof JDBCConnectionException) {
|
|
||||||
return new DataAccessResourceFailureException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof SQLGrammarException) {
|
|
||||||
SQLGrammarException jdbcEx = (SQLGrammarException) ex;
|
|
||||||
return new InvalidDataAccessResourceUsageException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof QueryTimeoutException) {
|
|
||||||
QueryTimeoutException jdbcEx = (QueryTimeoutException) ex;
|
|
||||||
return new org.springframework.dao.QueryTimeoutException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof LockAcquisitionException) {
|
|
||||||
LockAcquisitionException jdbcEx = (LockAcquisitionException) ex;
|
|
||||||
return new CannotAcquireLockException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof PessimisticLockException) {
|
|
||||||
PessimisticLockException jdbcEx = (PessimisticLockException) ex;
|
|
||||||
return new PessimisticLockingFailureException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof ConstraintViolationException) {
|
|
||||||
ConstraintViolationException jdbcEx = (ConstraintViolationException) ex;
|
|
||||||
return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() +
|
|
||||||
"]; constraint [" + jdbcEx.getConstraintName() + "]", ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof DataException) {
|
|
||||||
DataException jdbcEx = (DataException) ex;
|
|
||||||
return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof JDBCException) {
|
|
||||||
return new HibernateJdbcException((JDBCException) ex);
|
|
||||||
}
|
|
||||||
// end of JDBCException (subclass) handling
|
|
||||||
|
|
||||||
if (ex instanceof QueryException) {
|
|
||||||
return new HibernateQueryException((QueryException) ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof NonUniqueResultException) {
|
|
||||||
return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof NonUniqueObjectException) {
|
|
||||||
return new DuplicateKeyException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof PropertyValueException) {
|
|
||||||
return new DataIntegrityViolationException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof PersistentObjectException) {
|
|
||||||
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof TransientObjectException) {
|
|
||||||
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof ObjectDeletedException) {
|
|
||||||
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof UnresolvableObjectException) {
|
|
||||||
return new HibernateObjectRetrievalFailureException((UnresolvableObjectException) ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof WrongClassException) {
|
|
||||||
return new HibernateObjectRetrievalFailureException((WrongClassException) ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof StaleObjectStateException) {
|
|
||||||
return new HibernateOptimisticLockingFailureException((StaleObjectStateException) ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof StaleStateException) {
|
|
||||||
return new HibernateOptimisticLockingFailureException((StaleStateException) ex);
|
|
||||||
}
|
|
||||||
if (ex instanceof OptimisticLockException) {
|
|
||||||
return new HibernateOptimisticLockingFailureException((OptimisticLockException) ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// fallback
|
|
||||||
return new HibernateSystemException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether deferred close is active for the current thread
|
|
||||||
* and the given SessionFactory.
|
|
||||||
* @param sessionFactory the Hibernate SessionFactory to check
|
|
||||||
* @return whether deferred close is active
|
|
||||||
*/
|
|
||||||
public static boolean isDeferredCloseActive(SessionFactory sessionFactory) {
|
|
||||||
Assert.notNull(sessionFactory, "No SessionFactory specified");
|
|
||||||
Map<SessionFactory, Set<Session>> holderMap = deferredCloseHolder.get();
|
|
||||||
return (holderMap != null && holderMap.containsKey(sessionFactory));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize deferred close for the current thread and the given SessionFactory.
|
|
||||||
* Sessions will not be actually closed on close calls then, but rather at a
|
|
||||||
* {@link #processDeferredClose} call at a finishing point (like request completion).
|
|
||||||
* <p>Used by {@link org.springframework.orm.hibernate3.support.OpenSessionInViewFilter}
|
|
||||||
* and {@link org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor}
|
|
||||||
* when not configured for a single session.
|
|
||||||
* @param sessionFactory the Hibernate SessionFactory to initialize deferred close for
|
|
||||||
* @see #processDeferredClose
|
|
||||||
* @see #releaseSession
|
|
||||||
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter#setSingleSession
|
|
||||||
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor#setSingleSession
|
|
||||||
*/
|
|
||||||
public static void initDeferredClose(SessionFactory sessionFactory) {
|
|
||||||
Assert.notNull(sessionFactory, "No SessionFactory specified");
|
|
||||||
logger.debug("Initializing deferred close of Hibernate Sessions");
|
|
||||||
Map<SessionFactory, Set<Session>> holderMap = deferredCloseHolder.get();
|
|
||||||
if (holderMap == null) {
|
|
||||||
holderMap = new HashMap<SessionFactory, Set<Session>>();
|
|
||||||
deferredCloseHolder.set(holderMap);
|
|
||||||
}
|
|
||||||
holderMap.put(sessionFactory, new LinkedHashSet<Session>(4));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process all Hibernate Sessions that have been registered for deferred close
|
|
||||||
* for the given SessionFactory.
|
|
||||||
* @param sessionFactory the Hibernate SessionFactory to process deferred close for
|
|
||||||
* @see #initDeferredClose
|
|
||||||
* @see #releaseSession
|
|
||||||
*/
|
|
||||||
public static void processDeferredClose(SessionFactory sessionFactory) {
|
|
||||||
Assert.notNull(sessionFactory, "No SessionFactory specified");
|
|
||||||
Map<SessionFactory, Set<Session>> holderMap = deferredCloseHolder.get();
|
|
||||||
if (holderMap == null || !holderMap.containsKey(sessionFactory)) {
|
|
||||||
throw new IllegalStateException("Deferred close not active for SessionFactory [" + sessionFactory + "]");
|
|
||||||
}
|
|
||||||
logger.debug("Processing deferred close of Hibernate Sessions");
|
|
||||||
Set<Session> sessions = holderMap.remove(sessionFactory);
|
|
||||||
for (Session session : sessions) {
|
|
||||||
closeSession(session);
|
|
||||||
}
|
|
||||||
if (holderMap.isEmpty()) {
|
|
||||||
deferredCloseHolder.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the given Session, created via the given factory,
|
|
||||||
* if it is not managed externally (i.e. not bound to the thread).
|
|
||||||
* @param session the Hibernate Session to close (may be {@code null})
|
|
||||||
* @param sessionFactory Hibernate SessionFactory that the Session was created with
|
|
||||||
* (may be {@code null})
|
|
||||||
*/
|
|
||||||
public static void releaseSession(Session session, SessionFactory sessionFactory) {
|
|
||||||
if (session == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Only close non-transactional Sessions.
|
|
||||||
if (!isSessionTransactional(session, sessionFactory)) {
|
|
||||||
closeSessionOrRegisterDeferredClose(session, sessionFactory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the given Session or register it for deferred close.
|
|
||||||
* @param session the Hibernate Session to close
|
|
||||||
* @param sessionFactory Hibernate SessionFactory that the Session was created with
|
|
||||||
* (may be {@code null})
|
|
||||||
* @see #initDeferredClose
|
|
||||||
* @see #processDeferredClose
|
|
||||||
*/
|
|
||||||
static void closeSessionOrRegisterDeferredClose(Session session, SessionFactory sessionFactory) {
|
|
||||||
Map<SessionFactory, Set<Session>> holderMap = deferredCloseHolder.get();
|
|
||||||
if (holderMap != null && sessionFactory != null && holderMap.containsKey(sessionFactory)) {
|
|
||||||
logger.debug("Registering Hibernate Session for deferred close");
|
|
||||||
// Switch Session to FlushMode.MANUAL for remaining lifetime.
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
|
||||||
Set<Session> sessions = holderMap.get(sessionFactory);
|
|
||||||
sessions.add(session);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
closeSession(session);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform actual closing of the Hibernate Session,
|
|
||||||
* catching and logging any cleanup exceptions thrown.
|
|
||||||
* @param session the Hibernate Session to close (may be {@code null})
|
|
||||||
* @see org.hibernate.Session#close()
|
|
||||||
*/
|
|
||||||
public static void closeSession(Session session) {
|
|
||||||
if (session != null) {
|
|
||||||
logger.debug("Closing Hibernate Session");
|
|
||||||
try {
|
|
||||||
session.close();
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
logger.debug("Could not close Hibernate Session", ex);
|
|
||||||
}
|
|
||||||
catch (Throwable ex) {
|
|
||||||
logger.debug("Unexpected exception on closing Hibernate Session", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,151 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import org.hibernate.FlushMode;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.Transaction;
|
|
||||||
|
|
||||||
import org.springframework.transaction.support.ResourceHolderSupport;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Session holder, wrapping a Hibernate Session and a Hibernate Transaction.
|
|
||||||
* HibernateTransactionManager binds instances of this class to the thread,
|
|
||||||
* for a given SessionFactory.
|
|
||||||
*
|
|
||||||
* <p>Note: This is an SPI class, not intended to be used by applications.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see HibernateTransactionManager
|
|
||||||
* @see SessionFactoryUtils
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class SessionHolder extends ResourceHolderSupport {
|
|
||||||
|
|
||||||
private static final Object DEFAULT_KEY = new Object();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This Map needs to be concurrent because there might be multi-threaded
|
|
||||||
* access in the case of JTA with remote transaction propagation.
|
|
||||||
*/
|
|
||||||
private final Map<Object, Session> sessionMap = new ConcurrentHashMap<Object, Session>(1);
|
|
||||||
|
|
||||||
private Transaction transaction;
|
|
||||||
|
|
||||||
private FlushMode previousFlushMode;
|
|
||||||
|
|
||||||
|
|
||||||
public SessionHolder(Session session) {
|
|
||||||
addSession(session);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SessionHolder(Object key, Session session) {
|
|
||||||
addSession(key, session);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Session getSession() {
|
|
||||||
return getSession(DEFAULT_KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Session getSession(Object key) {
|
|
||||||
return this.sessionMap.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Session getValidatedSession() {
|
|
||||||
return getValidatedSession(DEFAULT_KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Session getValidatedSession(Object key) {
|
|
||||||
Session session = this.sessionMap.get(key);
|
|
||||||
// Check for dangling Session that's around but already closed.
|
|
||||||
// Effectively an assertion: that should never happen in practice.
|
|
||||||
// We'll seamlessly remove the Session here, to not let it cause
|
|
||||||
// any side effects.
|
|
||||||
if (session != null && !session.isOpen()) {
|
|
||||||
this.sessionMap.remove(key);
|
|
||||||
session = null;
|
|
||||||
}
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Session getAnySession() {
|
|
||||||
if (!this.sessionMap.isEmpty()) {
|
|
||||||
return this.sessionMap.values().iterator().next();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addSession(Session session) {
|
|
||||||
addSession(DEFAULT_KEY, session);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addSession(Object key, Session session) {
|
|
||||||
Assert.notNull(key, "Key must not be null");
|
|
||||||
Assert.notNull(session, "Session must not be null");
|
|
||||||
this.sessionMap.put(key, session);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Session removeSession(Object key) {
|
|
||||||
return this.sessionMap.remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean containsSession(Session session) {
|
|
||||||
return this.sessionMap.containsValue(session);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return this.sessionMap.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean doesNotHoldNonDefaultSession() {
|
|
||||||
return this.sessionMap.isEmpty() ||
|
|
||||||
(this.sessionMap.size() == 1 && this.sessionMap.containsKey(DEFAULT_KEY));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setTransaction(Transaction transaction) {
|
|
||||||
this.transaction = transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Transaction getTransaction() {
|
|
||||||
return this.transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPreviousFlushMode(FlushMode previousFlushMode) {
|
|
||||||
this.previousFlushMode = previousFlushMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FlushMode getPreviousFlushMode() {
|
|
||||||
return this.previousFlushMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
super.clear();
|
|
||||||
this.transaction = null;
|
|
||||||
this.previousFlushMode = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.classic.Session;
|
|
||||||
import org.hibernate.context.CurrentSessionContext;
|
|
||||||
import org.hibernate.engine.SessionFactoryImplementor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of Hibernate 3.1's CurrentSessionContext interface
|
|
||||||
* that delegates to Spring's SessionFactoryUtils for providing a
|
|
||||||
* Spring-managed current Session.
|
|
||||||
*
|
|
||||||
* <p>Used by Spring's {@link LocalSessionFactoryBean} when told to expose a
|
|
||||||
* transaction-aware SessionFactory. This is the default as of Spring 2.5.
|
|
||||||
*
|
|
||||||
* <p>This CurrentSessionContext implementation can also be specified in custom
|
|
||||||
* SessionFactory setup through the "hibernate.current_session_context_class"
|
|
||||||
* property, with the fully qualified name of this class as value.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 2.0
|
|
||||||
* @see SessionFactoryUtils#doGetSession
|
|
||||||
* @see LocalSessionFactoryBean#setExposeTransactionAwareSessionFactory
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class SpringSessionContext implements CurrentSessionContext {
|
|
||||||
|
|
||||||
private final SessionFactoryImplementor sessionFactory;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new SpringSessionContext for the given Hibernate SessionFactory.
|
|
||||||
* @param sessionFactory the SessionFactory to provide current Sessions for
|
|
||||||
*/
|
|
||||||
public SpringSessionContext(SessionFactoryImplementor sessionFactory) {
|
|
||||||
this.sessionFactory = sessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the Spring-managed Session for the current thread, if any.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Session currentSession() throws HibernateException {
|
|
||||||
try {
|
|
||||||
return (org.hibernate.classic.Session) SessionFactoryUtils.doGetSession(this.sessionFactory, false);
|
|
||||||
}
|
|
||||||
catch (IllegalStateException ex) {
|
|
||||||
throw new HibernateException(ex.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,268 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import javax.transaction.SystemException;
|
|
||||||
import javax.transaction.Transaction;
|
|
||||||
import javax.transaction.TransactionManager;
|
|
||||||
|
|
||||||
import org.hibernate.FlushMode;
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.JDBCException;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
import org.hibernate.engine.SessionImplementor;
|
|
||||||
|
|
||||||
import org.springframework.core.Ordered;
|
|
||||||
import org.springframework.dao.DataAccessException;
|
|
||||||
import org.springframework.dao.DataAccessResourceFailureException;
|
|
||||||
import org.springframework.jdbc.support.SQLExceptionTranslator;
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronization;
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for resource cleanup at the end of a Spring-managed JTA transaction,
|
|
||||||
* that is, when participating in a JtaTransactionManager transaction.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see SessionFactoryUtils
|
|
||||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
class SpringSessionSynchronization implements TransactionSynchronization, Ordered {
|
|
||||||
|
|
||||||
private final SessionHolder sessionHolder;
|
|
||||||
|
|
||||||
private final SessionFactory sessionFactory;
|
|
||||||
|
|
||||||
private final SQLExceptionTranslator jdbcExceptionTranslator;
|
|
||||||
|
|
||||||
private final boolean newSession;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether Hibernate has a looked-up JTA TransactionManager that it will
|
|
||||||
* automatically register CacheSynchronizations with on Session connect.
|
|
||||||
*/
|
|
||||||
private boolean hibernateTransactionCompletion = false;
|
|
||||||
|
|
||||||
private Transaction jtaTransaction;
|
|
||||||
|
|
||||||
private boolean holderActive = true;
|
|
||||||
|
|
||||||
|
|
||||||
public SpringSessionSynchronization(
|
|
||||||
SessionHolder sessionHolder, SessionFactory sessionFactory,
|
|
||||||
SQLExceptionTranslator jdbcExceptionTranslator, boolean newSession) {
|
|
||||||
|
|
||||||
this.sessionHolder = sessionHolder;
|
|
||||||
this.sessionFactory = sessionFactory;
|
|
||||||
this.jdbcExceptionTranslator = jdbcExceptionTranslator;
|
|
||||||
this.newSession = newSession;
|
|
||||||
|
|
||||||
// Check whether the SessionFactory has a JTA TransactionManager.
|
|
||||||
TransactionManager jtaTm =
|
|
||||||
SessionFactoryUtils.getJtaTransactionManager(sessionFactory, sessionHolder.getAnySession());
|
|
||||||
if (jtaTm != null) {
|
|
||||||
this.hibernateTransactionCompletion = true;
|
|
||||||
// Fetch current JTA Transaction object
|
|
||||||
// (just necessary for JTA transaction suspension, with an individual
|
|
||||||
// Hibernate Session per currently active/suspended transaction).
|
|
||||||
try {
|
|
||||||
this.jtaTransaction = jtaTm.getTransaction();
|
|
||||||
}
|
|
||||||
catch (SystemException ex) {
|
|
||||||
throw new DataAccessResourceFailureException("Could not access JTA transaction", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether there is a Hibernate Session for the current JTA
|
|
||||||
* transaction. Else, fall back to the default thread-bound Session.
|
|
||||||
*/
|
|
||||||
private Session getCurrentSession() {
|
|
||||||
Session session = null;
|
|
||||||
if (this.jtaTransaction != null) {
|
|
||||||
session = this.sessionHolder.getSession(this.jtaTransaction);
|
|
||||||
}
|
|
||||||
if (session == null) {
|
|
||||||
session = this.sessionHolder.getSession();
|
|
||||||
}
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getOrder() {
|
|
||||||
return SessionFactoryUtils.SESSION_SYNCHRONIZATION_ORDER;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void suspend() {
|
|
||||||
if (this.holderActive) {
|
|
||||||
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
|
|
||||||
// Eagerly disconnect the Session here, to make release mode "on_close" work on JBoss.
|
|
||||||
getCurrentSession().disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void resume() {
|
|
||||||
if (this.holderActive) {
|
|
||||||
TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void flush() {
|
|
||||||
try {
|
|
||||||
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on explicit request");
|
|
||||||
getCurrentSession().flush();
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
throw translateException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void beforeCommit(boolean readOnly) throws DataAccessException {
|
|
||||||
if (!readOnly) {
|
|
||||||
Session session = getCurrentSession();
|
|
||||||
// Read-write transaction -> flush the Hibernate Session.
|
|
||||||
// Further check: only flush when not FlushMode.NEVER/MANUAL.
|
|
||||||
if (!session.getFlushMode().lessThan(FlushMode.COMMIT)) {
|
|
||||||
try {
|
|
||||||
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on transaction synchronization");
|
|
||||||
session.flush();
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
throw translateException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private DataAccessException translateException(HibernateException ex) {
|
|
||||||
if (this.jdbcExceptionTranslator != null && ex instanceof JDBCException) {
|
|
||||||
JDBCException jdbcEx = (JDBCException) ex;
|
|
||||||
return this.jdbcExceptionTranslator.translate(
|
|
||||||
"Hibernate flushing: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException());
|
|
||||||
}
|
|
||||||
return SessionFactoryUtils.convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void beforeCompletion() {
|
|
||||||
if (this.jtaTransaction != null) {
|
|
||||||
// Typically in case of a suspended JTA transaction:
|
|
||||||
// Remove the Session for the current JTA transaction, but keep the holder.
|
|
||||||
Session session = this.sessionHolder.removeSession(this.jtaTransaction);
|
|
||||||
if (session != null) {
|
|
||||||
if (this.sessionHolder.isEmpty()) {
|
|
||||||
// No Sessions for JTA transactions bound anymore -> could remove it.
|
|
||||||
TransactionSynchronizationManager.unbindResourceIfPossible(this.sessionFactory);
|
|
||||||
this.holderActive = false;
|
|
||||||
}
|
|
||||||
// Do not close a pre-bound Session. In that case, we'll find the
|
|
||||||
// transaction-specific Session the same as the default Session.
|
|
||||||
if (session != this.sessionHolder.getSession()) {
|
|
||||||
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, this.sessionFactory);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (this.sessionHolder.getPreviousFlushMode() != null) {
|
|
||||||
// In case of pre-bound Session, restore previous flush mode.
|
|
||||||
session.setFlushMode(this.sessionHolder.getPreviousFlushMode());
|
|
||||||
}
|
|
||||||
// Eagerly disconnect the Session here, to make release mode "on_close" work nicely.
|
|
||||||
session.disconnect();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// We'll only get here if there was no specific JTA transaction to handle.
|
|
||||||
if (this.newSession) {
|
|
||||||
// Default behavior: unbind and close the thread-bound Hibernate Session.
|
|
||||||
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
|
|
||||||
this.holderActive = false;
|
|
||||||
if (this.hibernateTransactionCompletion) {
|
|
||||||
// Close the Hibernate Session here in case of a Hibernate TransactionManagerLookup:
|
|
||||||
// Hibernate will automatically defer the actual closing until JTA transaction completion.
|
|
||||||
// Else, the Session will be closed in the afterCompletion method, to provide the
|
|
||||||
// correct transaction status for releasing the Session's cache locks.
|
|
||||||
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(this.sessionHolder.getSession(), this.sessionFactory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Session session = this.sessionHolder.getSession();
|
|
||||||
if (this.sessionHolder.getPreviousFlushMode() != null) {
|
|
||||||
// In case of pre-bound Session, restore previous flush mode.
|
|
||||||
session.setFlushMode(this.sessionHolder.getPreviousFlushMode());
|
|
||||||
}
|
|
||||||
if (this.hibernateTransactionCompletion) {
|
|
||||||
// Eagerly disconnect the Session here, to make release mode "on_close" work nicely.
|
|
||||||
// We know that this is appropriate if a TransactionManagerLookup has been specified.
|
|
||||||
session.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterCommit() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterCompletion(int status) {
|
|
||||||
try {
|
|
||||||
if (!this.hibernateTransactionCompletion || !this.newSession) {
|
|
||||||
// No Hibernate TransactionManagerLookup: apply afterTransactionCompletion callback.
|
|
||||||
// Always perform explicit afterTransactionCompletion callback for pre-bound Session,
|
|
||||||
// even with Hibernate TransactionManagerLookup (which only applies to new Sessions).
|
|
||||||
Session session = this.sessionHolder.getSession();
|
|
||||||
// Provide correct transaction status for releasing the Session's cache locks,
|
|
||||||
// if possible. Else, closing will release all cache locks assuming a rollback.
|
|
||||||
try {
|
|
||||||
if (session instanceof SessionImplementor) {
|
|
||||||
((SessionImplementor) session).afterTransactionCompletion(status == STATUS_COMMITTED, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
// Close the Hibernate Session here if necessary
|
|
||||||
// (closed in beforeCompletion in case of TransactionManagerLookup).
|
|
||||||
if (this.newSession) {
|
|
||||||
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, this.sessionFactory);
|
|
||||||
}
|
|
||||||
else if (!this.hibernateTransactionCompletion) {
|
|
||||||
session.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!this.newSession && status != STATUS_COMMITTED) {
|
|
||||||
// Clear all pending inserts/updates/deletes in the Session.
|
|
||||||
// Necessary for pre-bound Sessions, to avoid inconsistent state.
|
|
||||||
this.sessionHolder.getSession().clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if (this.sessionHolder.doesNotHoldNonDefaultSession()) {
|
|
||||||
this.sessionHolder.setSynchronizedWithTransaction(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,83 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
import org.hibernate.ConnectionReleaseMode;
|
|
||||||
import org.hibernate.Transaction;
|
|
||||||
import org.hibernate.jdbc.JDBCContext;
|
|
||||||
import org.hibernate.transaction.JDBCTransaction;
|
|
||||||
import org.hibernate.transaction.TransactionFactory;
|
|
||||||
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spring-aware implementation of the Hibernate TransactionFactory interface, aware of
|
|
||||||
* Spring-synchronized transactions (in particular Spring-managed JTA transactions)
|
|
||||||
* and asking for default release mode ON_CLOSE. Otherwise identical to Hibernate's
|
|
||||||
* default {@link org.hibernate.transaction.JDBCTransactionFactory} implementation.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 2.5.4
|
|
||||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
|
||||||
* @see org.hibernate.transaction.JDBCTransactionFactory
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class SpringTransactionFactory implements TransactionFactory {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets connection release mode "on_close" as default.
|
|
||||||
* <p>This was the case for Hibernate 3.0; Hibernate 3.1 changed
|
|
||||||
* it to "auto" (i.e. "after_statement" or "after_transaction").
|
|
||||||
* However, for Spring's resource management (in particular for
|
|
||||||
* HibernateTransactionManager), "on_close" is the better default.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public ConnectionReleaseMode getDefaultReleaseMode() {
|
|
||||||
return ConnectionReleaseMode.ON_CLOSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext) {
|
|
||||||
return new JDBCTransaction(jdbcContext, transactionContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void configure(Properties props) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isTransactionManagerRequired() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean areCallbacksLocalToHibernateTransactions() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isTransactionInProgress(
|
|
||||||
JDBCContext jdbcContext, Context transactionContext, Transaction transaction) {
|
|
||||||
|
|
||||||
return (transaction != null && transaction.isActive()) ||
|
|
||||||
TransactionSynchronizationManager.isActualTransactionActive();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
|
|
||||||
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subclass of LocalDataSourceConnectionProvider that returns a
|
|
||||||
* transaction-aware proxy for the exposed DataSource. Used if
|
|
||||||
* LocalSessionFactoryBean's "useTransactionAwareDataSource" flag is on.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see LocalSessionFactoryBean#setUseTransactionAwareDataSource
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class TransactionAwareDataSourceConnectionProvider extends LocalDataSourceConnectionProvider {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a TransactionAwareDataSourceProxy for the given DataSource,
|
|
||||||
* provided that it isn't a TransactionAwareDataSourceProxy already.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected DataSource getDataSourceToUse(DataSource originalDataSource) {
|
|
||||||
if (originalDataSource instanceof TransactionAwareDataSourceProxy) {
|
|
||||||
return originalDataSource;
|
|
||||||
}
|
|
||||||
return new TransactionAwareDataSourceProxy(originalDataSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation returns {@code true}: We can guarantee
|
|
||||||
* to receive the same Connection within a transaction, as we are
|
|
||||||
* exposing a TransactionAwareDataSourceProxy.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean supportsAggressiveRelease() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,133 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.BeanNameAware;
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bean that encapsulates a Hibernate type definition.
|
|
||||||
*
|
|
||||||
* <p>Typically defined as inner bean within a LocalSessionFactoryBean
|
|
||||||
* definition, as list element for the "typeDefinitions" bean property.
|
|
||||||
* For example:
|
|
||||||
*
|
|
||||||
* <pre class="code">
|
|
||||||
* <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
|
|
||||||
* ...
|
|
||||||
* <property name="typeDefinitions">
|
|
||||||
* <list>
|
|
||||||
* <bean class="org.springframework.orm.hibernate3.TypeDefinitionBean">
|
|
||||||
* <property name="typeName" value="myType"/>
|
|
||||||
* <property name="typeClass" value="mypackage.MyTypeClass"/>
|
|
||||||
* </bean>
|
|
||||||
* </list>
|
|
||||||
* </property>
|
|
||||||
* ...
|
|
||||||
* </bean></pre>
|
|
||||||
*
|
|
||||||
* Alternatively, specify a bean id (or name) attribute for the inner bean,
|
|
||||||
* instead of the "typeName" property.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see LocalSessionFactoryBean#setTypeDefinitions(TypeDefinitionBean[])
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class TypeDefinitionBean implements BeanNameAware, InitializingBean {
|
|
||||||
|
|
||||||
private String typeName;
|
|
||||||
|
|
||||||
private String typeClass;
|
|
||||||
|
|
||||||
private Properties parameters = new Properties();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the name of the type.
|
|
||||||
* @see org.hibernate.cfg.Mappings#addTypeDef(String, String, java.util.Properties)
|
|
||||||
*/
|
|
||||||
public void setTypeName(String typeName) {
|
|
||||||
this.typeName = typeName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the name of the type.
|
|
||||||
*/
|
|
||||||
public String getTypeName() {
|
|
||||||
return typeName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the type implementation class.
|
|
||||||
* @see org.hibernate.cfg.Mappings#addTypeDef(String, String, java.util.Properties)
|
|
||||||
*/
|
|
||||||
public void setTypeClass(String typeClass) {
|
|
||||||
this.typeClass = typeClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the type implementation class.
|
|
||||||
*/
|
|
||||||
public String getTypeClass() {
|
|
||||||
return typeClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify default parameters for the type.
|
|
||||||
* This only applies to parameterized types.
|
|
||||||
* @see org.hibernate.cfg.Mappings#addTypeDef(String, String, java.util.Properties)
|
|
||||||
* @see org.hibernate.usertype.ParameterizedType
|
|
||||||
*/
|
|
||||||
public void setParameters(Properties parameters) {
|
|
||||||
this.parameters = parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the default parameters for the type.
|
|
||||||
*/
|
|
||||||
public Properties getParameters() {
|
|
||||||
return parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If no explicit type name has been specified, the bean name of
|
|
||||||
* the TypeDefinitionBean will be used.
|
|
||||||
* @see #setTypeName
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void setBeanName(String name) {
|
|
||||||
if (this.typeName == null) {
|
|
||||||
this.typeName = name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterPropertiesSet() {
|
|
||||||
if (this.typeName == null) {
|
|
||||||
throw new IllegalArgumentException("typeName is required");
|
|
||||||
}
|
|
||||||
if (this.typeClass == null) {
|
|
||||||
throw new IllegalArgumentException("typeClass is required");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,228 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3.annotation;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
import javax.persistence.Embeddable;
|
|
||||||
import javax.persistence.Entity;
|
|
||||||
import javax.persistence.MappedSuperclass;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.MappingException;
|
|
||||||
import org.hibernate.cfg.Configuration;
|
|
||||||
|
|
||||||
import org.springframework.context.ResourceLoaderAware;
|
|
||||||
import org.springframework.core.io.Resource;
|
|
||||||
import org.springframework.core.io.ResourceLoader;
|
|
||||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
|
||||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
|
||||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
|
||||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
|
||||||
import org.springframework.core.type.classreading.MetadataReader;
|
|
||||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
|
||||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
|
||||||
import org.springframework.core.type.filter.TypeFilter;
|
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subclass of Spring's standard LocalSessionFactoryBean for Hibernate,
|
|
||||||
* supporting annotation metadata for mappings.
|
|
||||||
*
|
|
||||||
* <p>Example for an AnnotationSessionFactoryBean bean definition:
|
|
||||||
*
|
|
||||||
* <pre class="code">
|
|
||||||
* <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
|
|
||||||
* <property name="dataSource" ref="dataSource"/>
|
|
||||||
* <property name="annotatedClasses">
|
|
||||||
* <list>
|
|
||||||
* <value>test.package.Foo</value>
|
|
||||||
* <value>test.package.Bar</value>
|
|
||||||
* </list>
|
|
||||||
* </property>
|
|
||||||
* </bean></pre>
|
|
||||||
*
|
|
||||||
* Or when using classpath scanning for autodetection of entity classes:
|
|
||||||
*
|
|
||||||
* <pre class="code">
|
|
||||||
* <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
|
|
||||||
* <property name="dataSource" ref="dataSource"/>
|
|
||||||
* <property name="packagesToScan" value="test.package"/>
|
|
||||||
* </bean></pre>
|
|
||||||
*
|
|
||||||
* <p>Requires Hibernate 3.6.x, as of Spring 4.0.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2.2
|
|
||||||
* @see #setDataSource
|
|
||||||
* @see #setHibernateProperties
|
|
||||||
* @see #setAnnotatedClasses
|
|
||||||
* @see #setAnnotatedPackages
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class AnnotationSessionFactoryBean extends org.springframework.orm.hibernate3.LocalSessionFactoryBean
|
|
||||||
implements ResourceLoaderAware {
|
|
||||||
|
|
||||||
private static final String RESOURCE_PATTERN = "/**/*.class";
|
|
||||||
|
|
||||||
private static final String PACKAGE_INFO_SUFFIX = ".package-info";
|
|
||||||
|
|
||||||
|
|
||||||
private Class<?>[] annotatedClasses;
|
|
||||||
|
|
||||||
private String[] annotatedPackages;
|
|
||||||
|
|
||||||
private String[] packagesToScan;
|
|
||||||
|
|
||||||
private TypeFilter[] entityTypeFilters = new TypeFilter[] {
|
|
||||||
new AnnotationTypeFilter(Entity.class, false),
|
|
||||||
new AnnotationTypeFilter(Embeddable.class, false),
|
|
||||||
new AnnotationTypeFilter(MappedSuperclass.class, false),
|
|
||||||
new AnnotationTypeFilter(org.hibernate.annotations.Entity.class, false)};
|
|
||||||
|
|
||||||
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify annotated classes, for which mappings will be read from
|
|
||||||
* class-level annotation metadata.
|
|
||||||
* @see org.hibernate.cfg.Configuration#addAnnotatedClass(Class)
|
|
||||||
*/
|
|
||||||
public void setAnnotatedClasses(Class<?>... annotatedClasses) {
|
|
||||||
this.annotatedClasses = annotatedClasses;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the names of annotated packages, for which package-level
|
|
||||||
* annotation metadata will be read.
|
|
||||||
* @see org.hibernate.cfg.Configuration#addPackage(String)
|
|
||||||
*/
|
|
||||||
public void setAnnotatedPackages(String... annotatedPackages) {
|
|
||||||
this.annotatedPackages = annotatedPackages;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify packages to search using Spring-based scanning for entity classes in
|
|
||||||
* the classpath. This is an alternative to listing annotated classes explicitly.
|
|
||||||
* <p>Default is none. Specify packages to search for autodetection of your entity
|
|
||||||
* classes in the classpath. This is analogous to Spring's component-scan feature
|
|
||||||
* ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}).
|
|
||||||
*/
|
|
||||||
public void setPackagesToScan(String... packagesToScan) {
|
|
||||||
this.packagesToScan = packagesToScan;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify custom type filters for Spring-based scanning for entity classes.
|
|
||||||
* <p>Default is to search all specified packages for classes annotated with
|
|
||||||
* {@code @javax.persistence.Entity}, {@code @javax.persistence.Embeddable}
|
|
||||||
* or {@code @javax.persistence.MappedSuperclass}, as well as for
|
|
||||||
* Hibernate's special {@code @org.hibernate.annotations.Entity}.
|
|
||||||
* @see #setPackagesToScan
|
|
||||||
*/
|
|
||||||
public void setEntityTypeFilters(TypeFilter... entityTypeFilters) {
|
|
||||||
this.entityTypeFilters = entityTypeFilters;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
|
||||||
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads metadata from annotated classes and packages into the
|
|
||||||
* AnnotationConfiguration instance.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void postProcessMappings(Configuration config) throws HibernateException {
|
|
||||||
if (this.annotatedClasses != null) {
|
|
||||||
for (Class<?> annotatedClass : this.annotatedClasses) {
|
|
||||||
config.addAnnotatedClass(annotatedClass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.annotatedPackages != null) {
|
|
||||||
for (String annotatedPackage : this.annotatedPackages) {
|
|
||||||
config.addPackage(annotatedPackage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scanPackages(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform Spring-based scanning for entity classes.
|
|
||||||
* @see #setPackagesToScan
|
|
||||||
*/
|
|
||||||
protected void scanPackages(Configuration config) {
|
|
||||||
if (this.packagesToScan != null) {
|
|
||||||
Set<String> classNames = new TreeSet<String>();
|
|
||||||
Set<String> packageNames = new TreeSet<String>();
|
|
||||||
try {
|
|
||||||
for (String pkg : this.packagesToScan) {
|
|
||||||
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
|
|
||||||
ClassUtils.convertClassNameToResourcePath(pkg) + RESOURCE_PATTERN;
|
|
||||||
Resource[] resources = this.resourcePatternResolver.getResources(pattern);
|
|
||||||
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
|
|
||||||
for (Resource resource : resources) {
|
|
||||||
if (resource.isReadable()) {
|
|
||||||
MetadataReader reader = readerFactory.getMetadataReader(resource);
|
|
||||||
String className = reader.getClassMetadata().getClassName();
|
|
||||||
if (matchesEntityTypeFilter(reader, readerFactory)) {
|
|
||||||
classNames.add(className);
|
|
||||||
}
|
|
||||||
else if (className.endsWith(PACKAGE_INFO_SUFFIX)) {
|
|
||||||
packageNames.add(className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException ex) {
|
|
||||||
throw new MappingException("Failed to scan classpath for unlisted classes", ex);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
for (String className : classNames) {
|
|
||||||
config.addAnnotatedClass(this.resourcePatternResolver.getClassLoader().loadClass(className));
|
|
||||||
}
|
|
||||||
for (String packageName : packageNames) {
|
|
||||||
config.addPackage(packageName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ClassNotFoundException ex) {
|
|
||||||
throw new MappingException("Failed to load annotated classes from classpath", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether any of the configured entity type filters matches
|
|
||||||
* the current class descriptor contained in the metadata reader.
|
|
||||||
*/
|
|
||||||
private boolean matchesEntityTypeFilter(MetadataReader reader, MetadataReaderFactory readerFactory) throws IOException {
|
|
||||||
if (this.entityTypeFilters != null) {
|
|
||||||
for (TypeFilter filter : this.entityTypeFilters) {
|
|
||||||
if (filter.match(reader, readerFactory)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
/**
|
|
||||||
* Support package for the Hibernate 3 Annotation add-on,
|
|
||||||
* which supports JPA-compliant Java 5+ annotations for mappings.
|
|
||||||
*/
|
|
||||||
package org.springframework.orm.hibernate3.annotation;
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
/**
|
|
||||||
* Package providing integration of
|
|
||||||
* <a href="http://www.hibernate.org">Hibernate 3.x</a>
|
|
||||||
* with Spring concepts.
|
|
||||||
*
|
|
||||||
* <p>Contains SessionFactory helper classes, a template plus callback
|
|
||||||
* for Hibernate access, and an implementation of Spring's transaction SPI
|
|
||||||
* for local Hibernate transactions.
|
|
||||||
*
|
|
||||||
* <p><b>This package supports Hibernate 3.x only.</b>
|
|
||||||
* See the {@code org.springframework.orm.hibernate4} package for Hibernate 4.x support.
|
|
||||||
*/
|
|
||||||
package org.springframework.orm.hibernate3;
|
|
||||||
|
|
@ -1,223 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3.support;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import javax.transaction.TransactionManager;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.usertype.UserType;
|
|
||||||
import org.hibernate.util.EqualsHelper;
|
|
||||||
|
|
||||||
import org.springframework.jdbc.support.lob.LobCreator;
|
|
||||||
import org.springframework.jdbc.support.lob.LobCreatorUtils;
|
|
||||||
import org.springframework.jdbc.support.lob.LobHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract base class for Hibernate UserType implementations that map to LOBs.
|
|
||||||
* Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
|
|
||||||
*
|
|
||||||
* <p>For writing LOBs, either an active Spring transaction synchronization
|
|
||||||
* or an active JTA transaction (with "jtaTransactionManager" specified on
|
|
||||||
* LocalSessionFactoryBean or a Hibernate TransactionManagerLookup configured
|
|
||||||
* through the corresponding Hibernate property) is required.
|
|
||||||
*
|
|
||||||
* <p>Offers template methods for setting parameters and getting result values,
|
|
||||||
* passing in the LobHandler or LobCreator to use.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see org.springframework.jdbc.support.lob.LobHandler
|
|
||||||
* @see org.springframework.jdbc.support.lob.LobCreator
|
|
||||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
|
|
||||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setJtaTransactionManager
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public abstract class AbstractLobType implements UserType {
|
|
||||||
|
|
||||||
protected final Log logger = LogFactory.getLog(getClass());
|
|
||||||
|
|
||||||
private final LobHandler lobHandler;
|
|
||||||
|
|
||||||
private final TransactionManager jtaTransactionManager;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor used by Hibernate: fetches config-time LobHandler and
|
|
||||||
* config-time JTA TransactionManager from LocalSessionFactoryBean.
|
|
||||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
|
|
||||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
|
|
||||||
*/
|
|
||||||
protected AbstractLobType() {
|
|
||||||
this(org.springframework.orm.hibernate3.LocalSessionFactoryBean.getConfigTimeLobHandler(),
|
|
||||||
org.springframework.orm.hibernate3.LocalSessionFactoryBean.getConfigTimeTransactionManager());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor used for testing: takes an explicit LobHandler
|
|
||||||
* and an explicit JTA TransactionManager (can be {@code null}).
|
|
||||||
*/
|
|
||||||
protected AbstractLobType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
|
|
||||||
this.lobHandler = lobHandler;
|
|
||||||
this.jtaTransactionManager = jtaTransactionManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation returns false.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isMutable() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation delegates to the Hibernate EqualsHelper.
|
|
||||||
* @see org.hibernate.util.EqualsHelper#equals
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object x, Object y) throws HibernateException {
|
|
||||||
return EqualsHelper.equals(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation returns the hashCode of the given objectz.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int hashCode(Object x) throws HibernateException {
|
|
||||||
return x.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation returns the passed-in value as-is.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Object deepCopy(Object value) throws HibernateException {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation returns the passed-in value as-is.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Serializable disassemble(Object value) throws HibernateException {
|
|
||||||
return (Serializable) value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation returns the passed-in value as-is.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Object assemble(Serializable cached, Object owner) throws HibernateException {
|
|
||||||
return cached;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation returns the passed-in original as-is.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Object replace(Object original, Object target, Object owner) throws HibernateException {
|
|
||||||
return original;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation delegates to nullSafeGetInternal,
|
|
||||||
* passing in the LobHandler of this type.
|
|
||||||
* @see #nullSafeGetInternal
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public final Object nullSafeGet(ResultSet rs, String[] names, Object owner)
|
|
||||||
throws HibernateException, SQLException {
|
|
||||||
|
|
||||||
if (this.lobHandler == null) {
|
|
||||||
throw new IllegalStateException("No LobHandler found for configuration - " +
|
|
||||||
"lobHandler property must be set on LocalSessionFactoryBean");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return nullSafeGetInternal(rs, names, owner, this.lobHandler);
|
|
||||||
}
|
|
||||||
catch (IOException ex) {
|
|
||||||
throw new HibernateException("I/O errors during LOB access", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation delegates to nullSafeSetInternal,
|
|
||||||
* passing in a transaction-synchronized LobCreator for the
|
|
||||||
* LobHandler of this type.
|
|
||||||
* @see #nullSafeSetInternal
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public final void nullSafeSet(PreparedStatement st, Object value, int index)
|
|
||||||
throws HibernateException, SQLException {
|
|
||||||
|
|
||||||
if (this.lobHandler == null) {
|
|
||||||
throw new IllegalStateException("No LobHandler found for configuration - " +
|
|
||||||
"lobHandler property must be set on LocalSessionFactoryBean");
|
|
||||||
}
|
|
||||||
|
|
||||||
LobCreator lobCreator = this.lobHandler.getLobCreator();
|
|
||||||
try {
|
|
||||||
nullSafeSetInternal(st, index, value, lobCreator);
|
|
||||||
}
|
|
||||||
catch (IOException ex) {
|
|
||||||
throw new HibernateException("I/O errors during LOB access", ex);
|
|
||||||
}
|
|
||||||
LobCreatorUtils.registerTransactionSynchronization(lobCreator, this.jtaTransactionManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Template method to extract a value from the given result set.
|
|
||||||
* @param rs the ResultSet to extract from
|
|
||||||
* @param names the column names
|
|
||||||
* @param owner the containing entity
|
|
||||||
* @param lobHandler the LobHandler to use
|
|
||||||
* @return the extracted value
|
|
||||||
* @throws SQLException if thrown by JDBC methods
|
|
||||||
* @throws IOException if thrown by streaming methods
|
|
||||||
* @throws HibernateException in case of any other exceptions
|
|
||||||
*/
|
|
||||||
protected abstract Object nullSafeGetInternal(
|
|
||||||
ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
|
|
||||||
throws SQLException, IOException, HibernateException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Template method to set the given parameter value on the given statement.
|
|
||||||
* @param ps the PreparedStatement to set on
|
|
||||||
* @param index the statement parameter index
|
|
||||||
* @param value the value to set
|
|
||||||
* @param lobCreator the LobCreator to use
|
|
||||||
* @throws SQLException if thrown by JDBC methods
|
|
||||||
* @throws IOException if thrown by streaming methods
|
|
||||||
* @throws HibernateException in case of any other exceptions
|
|
||||||
*/
|
|
||||||
protected abstract void nullSafeSetInternal(
|
|
||||||
PreparedStatement ps, int index, Object value, LobCreator lobCreator)
|
|
||||||
throws SQLException, IOException, HibernateException;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,120 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2015 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3.support;
|
|
||||||
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
||||||
import org.springframework.web.context.request.NativeWebRequest;
|
|
||||||
import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
|
|
||||||
import org.springframework.web.context.request.async.DeferredResult;
|
|
||||||
import org.springframework.web.context.request.async.DeferredResultProcessingInterceptor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interceptor with asynchronous web requests used in OpenSessionInViewFilter and
|
|
||||||
* OpenSessionInViewInterceptor.
|
|
||||||
*
|
|
||||||
* Ensures the following:
|
|
||||||
* 1) The session is bound/unbound when "callable processing" is started
|
|
||||||
* 2) The session is closed if an async request times out
|
|
||||||
*
|
|
||||||
* @author Rossen Stoyanchev
|
|
||||||
* @since 3.2.5
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
class AsyncRequestInterceptor extends CallableProcessingInterceptorAdapter implements DeferredResultProcessingInterceptor {
|
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(AsyncRequestInterceptor.class);
|
|
||||||
|
|
||||||
private final SessionFactory sessionFactory;
|
|
||||||
|
|
||||||
private final org.springframework.orm.hibernate3.SessionHolder sessionHolder;
|
|
||||||
|
|
||||||
private volatile boolean timeoutInProgress;
|
|
||||||
|
|
||||||
|
|
||||||
public AsyncRequestInterceptor(SessionFactory sessionFactory, org.springframework.orm.hibernate3.SessionHolder sessionHolder) {
|
|
||||||
this.sessionFactory = sessionFactory;
|
|
||||||
this.sessionHolder = sessionHolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void preProcess(NativeWebRequest request, Callable<T> task) {
|
|
||||||
bindSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void bindSession() {
|
|
||||||
this.timeoutInProgress = false;
|
|
||||||
TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
|
|
||||||
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) {
|
|
||||||
this.timeoutInProgress = true;
|
|
||||||
return RESULT_NONE; // give other interceptors a chance to handle the timeout
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void afterCompletion(NativeWebRequest request, Callable<T> task) throws Exception {
|
|
||||||
closeAfterTimeout();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void closeAfterTimeout() {
|
|
||||||
if (this.timeoutInProgress) {
|
|
||||||
logger.debug("Closing Hibernate Session after async request timeout");
|
|
||||||
org.springframework.orm.hibernate3.SessionFactoryUtils.closeSession(this.sessionHolder.getSession());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Implementation of DeferredResultProcessingInterceptor methods
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void beforeConcurrentHandling(NativeWebRequest request, DeferredResult<T> deferredResult) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void preProcess(NativeWebRequest request, DeferredResult<T> deferredResult) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void postProcess(NativeWebRequest request, DeferredResult<T> deferredResult, Object result) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> boolean handleTimeout(NativeWebRequest request, DeferredResult<T> deferredResult) {
|
|
||||||
this.timeoutInProgress = true;
|
|
||||||
return true; // give other interceptors a chance to handle the timeout
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void afterCompletion(NativeWebRequest request, DeferredResult<T> deferredResult) {
|
|
||||||
closeAfterTimeout();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,112 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3.support;
|
|
||||||
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Types;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import javax.transaction.TransactionManager;
|
|
||||||
|
|
||||||
import org.springframework.jdbc.support.lob.LobCreator;
|
|
||||||
import org.springframework.jdbc.support.lob.LobHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate UserType implementation for byte arrays that get mapped to BLOBs.
|
|
||||||
* Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
|
|
||||||
*
|
|
||||||
* <p>Can also be defined in generic Hibernate mappings, as DefaultLobCreator will
|
|
||||||
* work with most JDBC-compliant database drivers. In this case, the field type
|
|
||||||
* does not have to be BLOB: For databases like MySQL and MS SQL Server, any
|
|
||||||
* large enough binary type will work.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class BlobByteArrayType extends AbstractLobType {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor used by Hibernate: fetches config-time LobHandler and
|
|
||||||
* config-time JTA TransactionManager from LocalSessionFactoryBean.
|
|
||||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
|
|
||||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
|
|
||||||
*/
|
|
||||||
public BlobByteArrayType() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor used for testing: takes an explicit LobHandler
|
|
||||||
* and an explicit JTA TransactionManager (can be {@code null}).
|
|
||||||
*/
|
|
||||||
protected BlobByteArrayType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
|
|
||||||
super(lobHandler, jtaTransactionManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int[] sqlTypes() {
|
|
||||||
return new int[] {Types.BLOB};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?> returnedClass() {
|
|
||||||
return byte[].class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isMutable() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object x, Object y) {
|
|
||||||
return (x == y) ||
|
|
||||||
(x instanceof byte[] && y instanceof byte[] && Arrays.equals((byte[]) x, (byte[]) y));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object deepCopy(Object value) {
|
|
||||||
if (value == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
byte[] original = (byte[]) value;
|
|
||||||
byte[] copy = new byte[original.length];
|
|
||||||
System.arraycopy(original, 0, copy, 0, original.length);
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Object nullSafeGetInternal(
|
|
||||||
ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
|
|
||||||
throws SQLException {
|
|
||||||
|
|
||||||
return lobHandler.getBlobAsBytes(rs, names[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void nullSafeSetInternal(
|
|
||||||
PreparedStatement ps, int index, Object value, LobCreator lobCreator)
|
|
||||||
throws SQLException {
|
|
||||||
|
|
||||||
lobCreator.setBlobAsBytes(ps, index, (byte[]) value);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,171 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3.support;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Types;
|
|
||||||
import javax.transaction.TransactionManager;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
|
|
||||||
import org.springframework.jdbc.support.lob.LobCreator;
|
|
||||||
import org.springframework.jdbc.support.lob.LobHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate UserType implementation for arbitrary objects that get serialized to BLOBs.
|
|
||||||
* Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
|
|
||||||
*
|
|
||||||
* <p>Can also be defined in generic Hibernate mappings, as DefaultLobCreator will
|
|
||||||
* work with most JDBC-compliant database drivers. In this case, the field type
|
|
||||||
* does not have to be BLOB: For databases like MySQL and MS SQL Server, any
|
|
||||||
* large enough binary type will work.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class BlobSerializableType extends AbstractLobType {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initial size for ByteArrayOutputStreams used for serialization output.
|
|
||||||
* <p>If a serialized object is larger than these 1024 bytes, the size of
|
|
||||||
* the byte array used by the output stream will be doubled each time the
|
|
||||||
* limit is reached.
|
|
||||||
*/
|
|
||||||
private static final int OUTPUT_BYTE_ARRAY_INITIAL_SIZE = 1024;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor used by Hibernate: fetches config-time LobHandler and
|
|
||||||
* config-time JTA TransactionManager from LocalSessionFactoryBean.
|
|
||||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
|
|
||||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
|
|
||||||
*/
|
|
||||||
public BlobSerializableType() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor used for testing: takes an explicit LobHandler
|
|
||||||
* and an explicit JTA TransactionManager (can be {@code null}).
|
|
||||||
*/
|
|
||||||
protected BlobSerializableType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
|
|
||||||
super(lobHandler, jtaTransactionManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int[] sqlTypes() {
|
|
||||||
return new int[] {Types.BLOB};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?> returnedClass() {
|
|
||||||
return Serializable.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isMutable() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object deepCopy(Object value) throws HibernateException {
|
|
||||||
try {
|
|
||||||
// Write to new byte array to clone.
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(OUTPUT_BYTE_ARRAY_INITIAL_SIZE);
|
|
||||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
|
||||||
try {
|
|
||||||
oos.writeObject(value);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
oos.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read it back and return a true copy.
|
|
||||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
|
||||||
ObjectInputStream ois = new ObjectInputStream(bais);
|
|
||||||
try {
|
|
||||||
return ois.readObject();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
ois.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ClassNotFoundException ex) {
|
|
||||||
throw new HibernateException("Couldn't clone BLOB contents", ex);
|
|
||||||
}
|
|
||||||
catch (IOException ex) {
|
|
||||||
throw new HibernateException("Couldn't clone BLOB contents", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Object nullSafeGetInternal(
|
|
||||||
ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
|
|
||||||
throws SQLException, IOException, HibernateException {
|
|
||||||
|
|
||||||
InputStream is = lobHandler.getBlobAsBinaryStream(rs, names[0]);
|
|
||||||
if (is != null) {
|
|
||||||
ObjectInputStream ois = new ObjectInputStream(is);
|
|
||||||
try {
|
|
||||||
return ois.readObject();
|
|
||||||
}
|
|
||||||
catch (ClassNotFoundException ex) {
|
|
||||||
throw new HibernateException("Could not deserialize BLOB contents", ex);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
ois.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void nullSafeSetInternal(
|
|
||||||
PreparedStatement ps, int index, Object value, LobCreator lobCreator)
|
|
||||||
throws SQLException, IOException {
|
|
||||||
|
|
||||||
if (value != null) {
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(OUTPUT_BYTE_ARRAY_INITIAL_SIZE);
|
|
||||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
|
||||||
try {
|
|
||||||
oos.writeObject(value);
|
|
||||||
oos.flush();
|
|
||||||
lobCreator.setBlobAsBytes(ps, index, baos.toByteArray());
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
oos.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
lobCreator.setBlobAsBytes(ps, index, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,126 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3.support;
|
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Types;
|
|
||||||
import javax.transaction.TransactionManager;
|
|
||||||
|
|
||||||
import org.springframework.jdbc.support.lob.LobCreator;
|
|
||||||
import org.springframework.jdbc.support.lob.LobHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate UserType implementation for Strings that get mapped to BLOBs.
|
|
||||||
* Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
|
|
||||||
*
|
|
||||||
* <p>This is intended for the (arguably unnatural, but still common) case
|
|
||||||
* where character data is stored in a binary LOB. This requires encoding
|
|
||||||
* and decoding the characters within this UserType; see the javadoc of the
|
|
||||||
* {@code getCharacterEncoding()} method.
|
|
||||||
*
|
|
||||||
* <p>Can also be defined in generic Hibernate mappings, as DefaultLobCreator will
|
|
||||||
* work with most JDBC-compliant database drivers. In this case, the field type
|
|
||||||
* does not have to be BLOB: For databases like MySQL and MS SQL Server, any
|
|
||||||
* large enough binary type will work.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2.7
|
|
||||||
* @see #getCharacterEncoding()
|
|
||||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class BlobStringType extends AbstractLobType {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor used by Hibernate: fetches config-time LobHandler and
|
|
||||||
* config-time JTA TransactionManager from LocalSessionFactoryBean.
|
|
||||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
|
|
||||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
|
|
||||||
*/
|
|
||||||
public BlobStringType() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor used for testing: takes an explicit LobHandler
|
|
||||||
* and an explicit JTA TransactionManager (can be {@code null}).
|
|
||||||
*/
|
|
||||||
protected BlobStringType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
|
|
||||||
super(lobHandler, jtaTransactionManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int[] sqlTypes() {
|
|
||||||
return new int[] {Types.BLOB};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?> returnedClass() {
|
|
||||||
return String.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Object nullSafeGetInternal(
|
|
||||||
ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
|
|
||||||
throws SQLException, UnsupportedEncodingException {
|
|
||||||
|
|
||||||
byte[] bytes = lobHandler.getBlobAsBytes(rs, names[0]);
|
|
||||||
if (bytes != null) {
|
|
||||||
String encoding = getCharacterEncoding();
|
|
||||||
return (encoding != null ? new String(bytes, encoding) : new String(bytes));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void nullSafeSetInternal(
|
|
||||||
PreparedStatement ps, int index, Object value, LobCreator lobCreator)
|
|
||||||
throws SQLException, UnsupportedEncodingException {
|
|
||||||
|
|
||||||
if (value != null) {
|
|
||||||
String str = (String) value;
|
|
||||||
String encoding = getCharacterEncoding();
|
|
||||||
byte[] bytes = (encoding != null ? str.getBytes(encoding) : str.getBytes());
|
|
||||||
lobCreator.setBlobAsBytes(ps, index, bytes);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
lobCreator.setBlobAsBytes(ps, index, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine the character encoding to apply to the BLOB's bytes
|
|
||||||
* to turn them into a String.
|
|
||||||
* <p>Default is {@code null}, indicating to use the platform
|
|
||||||
* default encoding. To be overridden in subclasses for a specific
|
|
||||||
* encoding such as "ISO-8859-1" or "UTF-8".
|
|
||||||
* @return the character encoding to use, or {@code null}
|
|
||||||
* to use the platform default encoding
|
|
||||||
* @see String#String(byte[], String)
|
|
||||||
* @see String#getBytes(String)
|
|
||||||
*/
|
|
||||||
protected String getCharacterEncoding() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3.support;
|
|
||||||
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Types;
|
|
||||||
import javax.transaction.TransactionManager;
|
|
||||||
|
|
||||||
import org.springframework.jdbc.support.lob.LobCreator;
|
|
||||||
import org.springframework.jdbc.support.lob.LobHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate UserType implementation for Strings that get mapped to CLOBs.
|
|
||||||
* Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
|
|
||||||
*
|
|
||||||
* <p>Particularly useful for storing Strings with more than 4000 characters in an
|
|
||||||
* Oracle database (only possible via CLOBs), in combination with OracleLobHandler.
|
|
||||||
*
|
|
||||||
* <p>Can also be defined in generic Hibernate mappings, as DefaultLobCreator will
|
|
||||||
* work with most JDBC-compliant database drivers. In this case, the field type
|
|
||||||
* does not have to be CLOB: For databases like MySQL and MS SQL Server, any
|
|
||||||
* large enough character type will work.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class ClobStringType extends AbstractLobType {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor used by Hibernate: fetches config-time LobHandler and
|
|
||||||
* config-time JTA TransactionManager from LocalSessionFactoryBean.
|
|
||||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
|
|
||||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
|
|
||||||
*/
|
|
||||||
public ClobStringType() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor used for testing: takes an explicit LobHandler
|
|
||||||
* and an explicit JTA TransactionManager (can be {@code null}).
|
|
||||||
*/
|
|
||||||
protected ClobStringType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
|
|
||||||
super(lobHandler, jtaTransactionManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int[] sqlTypes() {
|
|
||||||
return new int[] {Types.CLOB};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?> returnedClass() {
|
|
||||||
return String.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Object nullSafeGetInternal(
|
|
||||||
ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
|
|
||||||
throws SQLException {
|
|
||||||
|
|
||||||
return lobHandler.getClobAsString(rs, names[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void nullSafeSetInternal(
|
|
||||||
PreparedStatement ps, int index, Object value, LobCreator lobCreator)
|
|
||||||
throws SQLException {
|
|
||||||
|
|
||||||
lobCreator.setClobAsString(ps, index, (String) value);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,216 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3.support;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException;
|
|
||||||
import org.springframework.dao.DataAccessResourceFailureException;
|
|
||||||
import org.springframework.dao.support.DaoSupport;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenient super class for Hibernate-based data access objects.
|
|
||||||
*
|
|
||||||
* <p>Requires a {@link org.hibernate.SessionFactory} to be set, providing a
|
|
||||||
* {@link org.springframework.orm.hibernate3.HibernateTemplate} based on it to
|
|
||||||
* subclasses through the {@link #getHibernateTemplate()} method.
|
|
||||||
* Can alternatively be initialized directly with a HibernateTemplate,
|
|
||||||
* in order to reuse the latter's settings such as the SessionFactory,
|
|
||||||
* exception translator, flush mode, etc.
|
|
||||||
*
|
|
||||||
* <p>This base class is mainly intended for HibernateTemplate usage but can
|
|
||||||
* also be used when working with a Hibernate Session directly, for example
|
|
||||||
* when relying on transactional Sessions. Convenience {@link #getSession}
|
|
||||||
* and {@link #releaseSession} methods are provided for that usage style.
|
|
||||||
*
|
|
||||||
* <p>This class will create its own HibernateTemplate instance if a SessionFactory
|
|
||||||
* is passed in. The "allowCreate" flag on that HibernateTemplate will be "true"
|
|
||||||
* by default. A custom HibernateTemplate instance can be used through overriding
|
|
||||||
* {@link #createHibernateTemplate}.
|
|
||||||
*
|
|
||||||
* <p><b>NOTE: As of Hibernate 3.0.1, transactional Hibernate access code can
|
|
||||||
* also be coded in plain Hibernate style. Hence, for newly started projects,
|
|
||||||
* consider adopting the standard Hibernate3 style of coding data access objects
|
|
||||||
* instead, based on {@link org.hibernate.SessionFactory#getCurrentSession()}.</b>
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see #setSessionFactory
|
|
||||||
* @see #getHibernateTemplate
|
|
||||||
* @see org.springframework.orm.hibernate3.HibernateTemplate
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public abstract class HibernateDaoSupport extends DaoSupport {
|
|
||||||
|
|
||||||
private org.springframework.orm.hibernate3.HibernateTemplate hibernateTemplate;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Hibernate SessionFactory to be used by this DAO.
|
|
||||||
* Will automatically create a HibernateTemplate for the given SessionFactory.
|
|
||||||
* @see #createHibernateTemplate
|
|
||||||
* @see #setHibernateTemplate
|
|
||||||
*/
|
|
||||||
public final void setSessionFactory(SessionFactory sessionFactory) {
|
|
||||||
if (this.hibernateTemplate == null || sessionFactory != this.hibernateTemplate.getSessionFactory()) {
|
|
||||||
this.hibernateTemplate = createHibernateTemplate(sessionFactory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a HibernateTemplate for the given SessionFactory.
|
|
||||||
* Only invoked if populating the DAO with a SessionFactory reference!
|
|
||||||
* <p>Can be overridden in subclasses to provide a HibernateTemplate instance
|
|
||||||
* with different configuration, or a custom HibernateTemplate subclass.
|
|
||||||
* @param sessionFactory the Hibernate SessionFactory to create a HibernateTemplate for
|
|
||||||
* @return the new HibernateTemplate instance
|
|
||||||
* @see #setSessionFactory
|
|
||||||
*/
|
|
||||||
protected org.springframework.orm.hibernate3.HibernateTemplate createHibernateTemplate(SessionFactory sessionFactory) {
|
|
||||||
return new org.springframework.orm.hibernate3.HibernateTemplate(sessionFactory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the Hibernate SessionFactory used by this DAO.
|
|
||||||
*/
|
|
||||||
public final SessionFactory getSessionFactory() {
|
|
||||||
return (this.hibernateTemplate != null ? this.hibernateTemplate.getSessionFactory() : null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the HibernateTemplate for this DAO explicitly,
|
|
||||||
* as an alternative to specifying a SessionFactory.
|
|
||||||
* @see #setSessionFactory
|
|
||||||
*/
|
|
||||||
public final void setHibernateTemplate(org.springframework.orm.hibernate3.HibernateTemplate hibernateTemplate) {
|
|
||||||
this.hibernateTemplate = hibernateTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the HibernateTemplate for this DAO,
|
|
||||||
* pre-initialized with the SessionFactory or set explicitly.
|
|
||||||
* <p><b>Note: The returned HibernateTemplate is a shared instance.</b>
|
|
||||||
* You may introspect its configuration, but not modify the configuration
|
|
||||||
* (other than from within an {@link #initDao} implementation).
|
|
||||||
* Consider creating a custom HibernateTemplate instance via
|
|
||||||
* {@code new HibernateTemplate(getSessionFactory())}, in which case
|
|
||||||
* you're allowed to customize the settings on the resulting instance.
|
|
||||||
*/
|
|
||||||
public final org.springframework.orm.hibernate3.HibernateTemplate getHibernateTemplate() {
|
|
||||||
return this.hibernateTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected final void checkDaoConfig() {
|
|
||||||
if (this.hibernateTemplate == null) {
|
|
||||||
throw new IllegalArgumentException("'sessionFactory' or 'hibernateTemplate' is required");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain a Hibernate Session, either from the current transaction or
|
|
||||||
* a new one. The latter is only allowed if the
|
|
||||||
* {@link org.springframework.orm.hibernate3.HibernateTemplate#setAllowCreate "allowCreate"}
|
|
||||||
* setting of this bean's {@link #setHibernateTemplate HibernateTemplate} is "true".
|
|
||||||
* <p><b>Note that this is not meant to be invoked from HibernateTemplate code
|
|
||||||
* but rather just in plain Hibernate code.</b> Either rely on a thread-bound
|
|
||||||
* Session or use it in combination with {@link #releaseSession}.
|
|
||||||
* <p>In general, it is recommended to use HibernateTemplate, either with
|
|
||||||
* the provided convenience operations or with a custom HibernateCallback
|
|
||||||
* that provides you with a Session to work on. HibernateTemplate will care
|
|
||||||
* for all resource management and for proper exception conversion.
|
|
||||||
* @return the Hibernate Session
|
|
||||||
* @throws DataAccessResourceFailureException if the Session couldn't be created
|
|
||||||
* @throws IllegalStateException if no thread-bound Session found and allowCreate=false
|
|
||||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)
|
|
||||||
* @deprecated as of Spring 3.2.7, in favor of {@link org.springframework.orm.hibernate3.HibernateTemplate} usage
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected final Session getSession() throws DataAccessResourceFailureException, IllegalStateException {
|
|
||||||
return getSession(this.hibernateTemplate.isAllowCreate());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain a Hibernate Session, either from the current transaction or
|
|
||||||
* a new one. The latter is only allowed if "allowCreate" is true.
|
|
||||||
* <p><b>Note that this is not meant to be invoked from HibernateTemplate code
|
|
||||||
* but rather just in plain Hibernate code.</b> Either rely on a thread-bound
|
|
||||||
* Session or use it in combination with {@link #releaseSession}.
|
|
||||||
* <p>In general, it is recommended to use
|
|
||||||
* {@link #getHibernateTemplate() HibernateTemplate}, either with
|
|
||||||
* the provided convenience operations or with a custom
|
|
||||||
* {@link org.springframework.orm.hibernate3.HibernateCallback} that
|
|
||||||
* provides you with a Session to work on. HibernateTemplate will care
|
|
||||||
* for all resource management and for proper exception conversion.
|
|
||||||
* @param allowCreate if a non-transactional Session should be created when no
|
|
||||||
* transactional Session can be found for the current thread
|
|
||||||
* @return the Hibernate Session
|
|
||||||
* @throws DataAccessResourceFailureException if the Session couldn't be created
|
|
||||||
* @throws IllegalStateException if no thread-bound Session found and allowCreate=false
|
|
||||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)
|
|
||||||
* @deprecated as of Spring 3.2.7, in favor of {@link org.springframework.orm.hibernate3.HibernateTemplate} usage
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected final Session getSession(boolean allowCreate)
|
|
||||||
throws DataAccessResourceFailureException, IllegalStateException {
|
|
||||||
|
|
||||||
return (!allowCreate ?
|
|
||||||
org.springframework.orm.hibernate3.SessionFactoryUtils.getSession(getSessionFactory(), false) :
|
|
||||||
org.springframework.orm.hibernate3.SessionFactoryUtils.getSession(
|
|
||||||
getSessionFactory(),
|
|
||||||
this.hibernateTemplate.getEntityInterceptor(),
|
|
||||||
this.hibernateTemplate.getJdbcExceptionTranslator()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the given HibernateException to an appropriate exception from the
|
|
||||||
* {@code org.springframework.dao} hierarchy. Will automatically detect
|
|
||||||
* wrapped SQLExceptions and convert them accordingly.
|
|
||||||
* <p>Delegates to the
|
|
||||||
* {@link org.springframework.orm.hibernate3.HibernateTemplate#convertHibernateAccessException}
|
|
||||||
* method of this DAO's HibernateTemplate.
|
|
||||||
* <p>Typically used in plain Hibernate code, in combination with
|
|
||||||
* {@link #getSession} and {@link #releaseSession}.
|
|
||||||
* @param ex HibernateException that occurred
|
|
||||||
* @return the corresponding DataAccessException instance
|
|
||||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#convertHibernateAccessException
|
|
||||||
* @deprecated as of Spring 3.2.7, in favor of {@link org.springframework.orm.hibernate3.HibernateTemplate} usage
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected final DataAccessException convertHibernateAccessException(HibernateException ex) {
|
|
||||||
return this.hibernateTemplate.convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the given Hibernate Session, created via this DAO's SessionFactory,
|
|
||||||
* if it isn't bound to the thread (i.e. isn't a transactional Session).
|
|
||||||
* <p>Typically used in plain Hibernate code, in combination with
|
|
||||||
* {@link #getSession} and {@link #convertHibernateAccessException}.
|
|
||||||
* @param session the Session to close
|
|
||||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#releaseSession
|
|
||||||
* @deprecated as of Spring 3.2.7, in favor of {@link org.springframework.orm.hibernate3.HibernateTemplate} usage
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected final void releaseSession(Session session) {
|
|
||||||
org.springframework.orm.hibernate3.SessionFactoryUtils.releaseSession(session, getSessionFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3.support;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.hibernate.engine.SessionImplementor;
|
|
||||||
import org.hibernate.event.MergeEvent;
|
|
||||||
import org.hibernate.event.def.DefaultMergeEventListener;
|
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension of Hibernate's DefaultMergeEventListener, transferring the ids
|
|
||||||
* of newly saved objects to the corresponding original objects (that are part
|
|
||||||
* of the detached object graph passed into the {@code merge} method).
|
|
||||||
*
|
|
||||||
* <p>Transferring newly assigned ids to the original graph allows for continuing
|
|
||||||
* to use the original object graph, despite merged copies being registered with
|
|
||||||
* the current Hibernate Session. This is particularly useful for web applications
|
|
||||||
* that might want to store an object graph and then render it in a web view,
|
|
||||||
* with links that include the id of certain (potentially newly saved) objects.
|
|
||||||
*
|
|
||||||
* <p>The merge behavior given by this MergeEventListener is nearly identical
|
|
||||||
* to TopLink's merge behavior. See PetClinic for an example, which relies on
|
|
||||||
* ids being available for newly saved objects: the {@code HibernateClinic}
|
|
||||||
* and {@code TopLinkClinic} DAO implementations both use straight merge
|
|
||||||
* calls, with the Hibernate SessionFactory configuration specifying an
|
|
||||||
* {@code IdTransferringMergeEventListener}.
|
|
||||||
*
|
|
||||||
* <p>Typically specified as entry for LocalSessionFactoryBean's "eventListeners"
|
|
||||||
* map, with key "merge".
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setEventListeners(java.util.Map)
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@SuppressWarnings({"serial", "rawtypes"})
|
|
||||||
public class IdTransferringMergeEventListener extends DefaultMergeEventListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate 3.1 implementation of ID transferral.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void entityIsTransient(MergeEvent event, Map copyCache) {
|
|
||||||
super.entityIsTransient(event, copyCache);
|
|
||||||
SessionImplementor session = event.getSession();
|
|
||||||
EntityPersister persister = session.getEntityPersister(event.getEntityName(), event.getEntity());
|
|
||||||
// Extract id from merged copy (which is currently registered with Session).
|
|
||||||
Serializable id = persister.getIdentifier(event.getResult(), session.getEntityMode());
|
|
||||||
// Set id on original object (which remains detached).
|
|
||||||
persister.setIdentifier(event.getOriginal(), id, session.getEntityMode());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,324 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2015 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3.support;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import javax.servlet.FilterChain;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import org.hibernate.FlushMode;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessResourceFailureException;
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.web.context.WebApplicationContext;
|
|
||||||
import org.springframework.web.context.request.async.WebAsyncManager;
|
|
||||||
import org.springframework.web.context.request.async.WebAsyncUtils;
|
|
||||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Servlet Filter that binds a Hibernate Session to the thread for the entire
|
|
||||||
* processing of the request. Intended for the "Open Session in View" pattern,
|
|
||||||
* i.e. to allow for lazy loading in web views despite the original transactions
|
|
||||||
* already being completed.
|
|
||||||
*
|
|
||||||
* <p>This filter makes Hibernate Sessions available via the current thread, which
|
|
||||||
* will be autodetected by transaction managers. It is suitable for service layer
|
|
||||||
* transactions via {@link org.springframework.orm.hibernate3.HibernateTransactionManager}
|
|
||||||
* or {@link org.springframework.transaction.jta.JtaTransactionManager} as well
|
|
||||||
* as for non-transactional execution (if configured appropriately).
|
|
||||||
*
|
|
||||||
* <p><b>NOTE</b>: This filter will by default <i>not</i> flush the Hibernate Session,
|
|
||||||
* with the flush mode set to {@code FlushMode.NEVER}. It assumes to be used
|
|
||||||
* in combination with service layer transactions that care for the flushing: The
|
|
||||||
* active transaction manager will temporarily change the flush mode to
|
|
||||||
* {@code FlushMode.AUTO} during a read-write transaction, with the flush
|
|
||||||
* mode reset to {@code FlushMode.NEVER} at the end of each transaction.
|
|
||||||
* If you intend to use this filter without transactions, consider changing
|
|
||||||
* the default flush mode (through the "flushMode" property).
|
|
||||||
*
|
|
||||||
* <p><b>WARNING:</b> Applying this filter to existing logic can cause issues that
|
|
||||||
* have not appeared before, through the use of a single Hibernate Session for the
|
|
||||||
* processing of an entire request. In particular, the reassociation of persistent
|
|
||||||
* objects with a Hibernate Session has to occur at the very beginning of request
|
|
||||||
* processing, to avoid clashes with already loaded instances of the same objects.
|
|
||||||
*
|
|
||||||
* <p>Alternatively, turn this filter into deferred close mode, by specifying
|
|
||||||
* "singleSession"="false": It will not use a single session per request then,
|
|
||||||
* but rather let each data access operation or transaction use its own session
|
|
||||||
* (like without Open Session in View). Each of those sessions will be registered
|
|
||||||
* for deferred close, though, actually processed at request completion.
|
|
||||||
*
|
|
||||||
* <p>A single session per request allows for most efficient first-level caching,
|
|
||||||
* but can cause side effects, for example on {@code saveOrUpdate} or when
|
|
||||||
* continuing after a rolled-back transaction. The deferred close strategy is as safe
|
|
||||||
* as no Open Session in View in that respect, while still allowing for lazy loading
|
|
||||||
* in views (but not providing a first-level cache for the entire request).
|
|
||||||
*
|
|
||||||
* <p>Looks up the SessionFactory in Spring's root web application context.
|
|
||||||
* Supports a "sessionFactoryBeanName" filter init-param in {@code web.xml};
|
|
||||||
* the default bean name is "sessionFactory".
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see #setSingleSession
|
|
||||||
* @see #setFlushMode
|
|
||||||
* @see #lookupSessionFactory
|
|
||||||
* @see OpenSessionInViewInterceptor
|
|
||||||
* @see OpenSessionInterceptor
|
|
||||||
* @see org.springframework.orm.hibernate3.HibernateTransactionManager
|
|
||||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession
|
|
||||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
|
||||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
|
||||||
|
|
||||||
public static final String DEFAULT_SESSION_FACTORY_BEAN_NAME = "sessionFactory";
|
|
||||||
|
|
||||||
|
|
||||||
private String sessionFactoryBeanName = DEFAULT_SESSION_FACTORY_BEAN_NAME;
|
|
||||||
|
|
||||||
private boolean singleSession = true;
|
|
||||||
|
|
||||||
private FlushMode flushMode = FlushMode.MANUAL;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the bean name of the SessionFactory to fetch from Spring's
|
|
||||||
* root application context. Default is "sessionFactory".
|
|
||||||
* @see #DEFAULT_SESSION_FACTORY_BEAN_NAME
|
|
||||||
*/
|
|
||||||
public void setSessionFactoryBeanName(String sessionFactoryBeanName) {
|
|
||||||
this.sessionFactoryBeanName = sessionFactoryBeanName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the bean name of the SessionFactory to fetch from Spring's
|
|
||||||
* root application context.
|
|
||||||
*/
|
|
||||||
protected String getSessionFactoryBeanName() {
|
|
||||||
return this.sessionFactoryBeanName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether to use a single session for each request. Default is "true".
|
|
||||||
* <p>If set to "false", each data access operation or transaction will use
|
|
||||||
* its own session (like without Open Session in View). Each of those
|
|
||||||
* sessions will be registered for deferred close, though, actually
|
|
||||||
* processed at request completion.
|
|
||||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#initDeferredClose
|
|
||||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#processDeferredClose
|
|
||||||
*/
|
|
||||||
public void setSingleSession(boolean singleSession) {
|
|
||||||
this.singleSession = singleSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return whether to use a single session for each request.
|
|
||||||
*/
|
|
||||||
protected boolean isSingleSession() {
|
|
||||||
return this.singleSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the Hibernate FlushMode to apply to this filter's
|
|
||||||
* {@link org.hibernate.Session}. Only applied in single session mode.
|
|
||||||
* <p>Can be populated with the corresponding constant name in XML bean
|
|
||||||
* definitions: e.g. "AUTO".
|
|
||||||
* <p>The default is "MANUAL". Specify "AUTO" if you intend to use
|
|
||||||
* this filter without service layer transactions.
|
|
||||||
* @see org.hibernate.Session#setFlushMode
|
|
||||||
* @see org.hibernate.FlushMode#MANUAL
|
|
||||||
* @see org.hibernate.FlushMode#AUTO
|
|
||||||
*/
|
|
||||||
public void setFlushMode(FlushMode flushMode) {
|
|
||||||
this.flushMode = flushMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the Hibernate FlushMode that this filter applies to its
|
|
||||||
* {@link org.hibernate.Session} (in single session mode).
|
|
||||||
*/
|
|
||||||
protected FlushMode getFlushMode() {
|
|
||||||
return this.flushMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns "false" so that the filter may re-bind the opened Hibernate
|
|
||||||
* {@code Session} to each asynchronously dispatched thread and postpone
|
|
||||||
* closing it until the very last asynchronous dispatch.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected boolean shouldNotFilterAsyncDispatch() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns "false" so that the filter may provide a Hibernate
|
|
||||||
* {@code Session} to each error dispatches.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected boolean shouldNotFilterErrorDispatch() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doFilterInternal(
|
|
||||||
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
|
||||||
throws ServletException, IOException {
|
|
||||||
|
|
||||||
SessionFactory sessionFactory = lookupSessionFactory(request);
|
|
||||||
boolean participate = false;
|
|
||||||
|
|
||||||
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
|
|
||||||
String key = getAlreadyFilteredAttributeName();
|
|
||||||
|
|
||||||
if (isSingleSession()) {
|
|
||||||
// single session mode
|
|
||||||
if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
|
|
||||||
// Do not modify the Session: just set the participate flag.
|
|
||||||
participate = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
boolean isFirstRequest = !isAsyncDispatch(request);
|
|
||||||
if (isFirstRequest || !applySessionBindingInterceptor(asyncManager, key)) {
|
|
||||||
logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
|
|
||||||
Session session = getSession(sessionFactory);
|
|
||||||
org.springframework.orm.hibernate3.SessionHolder sessionHolder = new org.springframework.orm.hibernate3.SessionHolder(session);
|
|
||||||
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
|
|
||||||
|
|
||||||
AsyncRequestInterceptor interceptor = new AsyncRequestInterceptor(sessionFactory, sessionHolder);
|
|
||||||
asyncManager.registerCallableInterceptor(key, interceptor);
|
|
||||||
asyncManager.registerDeferredResultInterceptor(key, interceptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// deferred close mode
|
|
||||||
Assert.state(!isAsyncStarted(request), "Deferred close mode is not supported on async dispatches");
|
|
||||||
if (org.springframework.orm.hibernate3.SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {
|
|
||||||
// Do not modify deferred close: just set the participate flag.
|
|
||||||
participate = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
org.springframework.orm.hibernate3.SessionFactoryUtils.initDeferredClose(sessionFactory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
filterChain.doFilter(request, response);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if (!participate) {
|
|
||||||
if (isSingleSession()) {
|
|
||||||
// single session mode
|
|
||||||
org.springframework.orm.hibernate3.SessionHolder sessionHolder =
|
|
||||||
(org.springframework.orm.hibernate3.SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
|
|
||||||
if (!isAsyncStarted(request)) {
|
|
||||||
logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
|
|
||||||
closeSession(sessionHolder.getSession(), sessionFactory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// deferred close mode
|
|
||||||
org.springframework.orm.hibernate3.SessionFactoryUtils.processDeferredClose(sessionFactory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Look up the SessionFactory that this filter should use,
|
|
||||||
* taking the current HTTP request as argument.
|
|
||||||
* <p>The default implementation delegates to the {@link #lookupSessionFactory()}
|
|
||||||
* variant without arguments.
|
|
||||||
* @param request the current request
|
|
||||||
* @return the SessionFactory to use
|
|
||||||
*/
|
|
||||||
protected SessionFactory lookupSessionFactory(HttpServletRequest request) {
|
|
||||||
return lookupSessionFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Look up the SessionFactory that this filter should use.
|
|
||||||
* <p>The default implementation looks for a bean with the specified name
|
|
||||||
* in Spring's root application context.
|
|
||||||
* @return the SessionFactory to use
|
|
||||||
* @see #getSessionFactoryBeanName
|
|
||||||
*/
|
|
||||||
protected SessionFactory lookupSessionFactory() {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Using SessionFactory '" + getSessionFactoryBeanName() + "' for OpenSessionInViewFilter");
|
|
||||||
}
|
|
||||||
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
|
|
||||||
return wac.getBean(getSessionFactoryBeanName(), SessionFactory.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a Session for the SessionFactory that this filter uses.
|
|
||||||
* Note that this just applies in single session mode!
|
|
||||||
* <p>The default implementation delegates to the
|
|
||||||
* {@code SessionFactoryUtils.getSession} method and
|
|
||||||
* sets the {@code Session}'s flush mode to "MANUAL".
|
|
||||||
* <p>Can be overridden in subclasses for creating a Session with a
|
|
||||||
* custom entity interceptor or JDBC exception translator.
|
|
||||||
* @param sessionFactory the SessionFactory that this filter uses
|
|
||||||
* @return the Session to use
|
|
||||||
* @throws DataAccessResourceFailureException if the Session could not be created
|
|
||||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)
|
|
||||||
* @see org.hibernate.FlushMode#MANUAL
|
|
||||||
*/
|
|
||||||
protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
|
|
||||||
Session session = org.springframework.orm.hibernate3.SessionFactoryUtils.getSession(sessionFactory, true);
|
|
||||||
FlushMode flushMode = getFlushMode();
|
|
||||||
if (flushMode != null) {
|
|
||||||
session.setFlushMode(flushMode);
|
|
||||||
}
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the given Session.
|
|
||||||
* Note that this just applies in single session mode!
|
|
||||||
* <p>Can be overridden in subclasses, e.g. for flushing the Session before
|
|
||||||
* closing it. See class-level javadoc for a discussion of flush handling.
|
|
||||||
* Note that you should also override getSession accordingly, to set
|
|
||||||
* the flush mode to something else than NEVER.
|
|
||||||
* @param session the Session used for filtering
|
|
||||||
* @param sessionFactory the SessionFactory that this filter uses
|
|
||||||
*/
|
|
||||||
protected void closeSession(Session session, SessionFactory sessionFactory) {
|
|
||||||
org.springframework.orm.hibernate3.SessionFactoryUtils.closeSession(session);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean applySessionBindingInterceptor(WebAsyncManager asyncManager, String key) {
|
|
||||||
if (asyncManager.getCallableInterceptor(key) == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,277 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3.support;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException;
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
||||||
import org.springframework.ui.ModelMap;
|
|
||||||
import org.springframework.web.context.request.AsyncWebRequestInterceptor;
|
|
||||||
import org.springframework.web.context.request.WebRequest;
|
|
||||||
import org.springframework.web.context.request.async.WebAsyncManager;
|
|
||||||
import org.springframework.web.context.request.async.WebAsyncUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spring web request interceptor that binds a Hibernate {@code Session} to the
|
|
||||||
* thread for the entire processing of the request.
|
|
||||||
*
|
|
||||||
* <p>This class is a concrete expression of the "Open Session in View" pattern, which
|
|
||||||
* is a pattern that allows for the lazy loading of associations in web views despite
|
|
||||||
* the original transactions already being completed.
|
|
||||||
*
|
|
||||||
* <p>This interceptor makes Hibernate {@code Sessions} available via the current
|
|
||||||
* thread, which will be autodetected by transaction managers. It is suitable for
|
|
||||||
* service layer transactions via
|
|
||||||
* {@link org.springframework.orm.hibernate3.HibernateTransactionManager} or
|
|
||||||
* {@link org.springframework.transaction.jta.JtaTransactionManager} as well as for
|
|
||||||
* non-transactional execution (if configured appropriately).
|
|
||||||
*
|
|
||||||
* <p><b>NOTE</b>: This interceptor will by default <i>not</i> flush the Hibernate
|
|
||||||
* {@code Session}, with the flush mode being set to {@code FlushMode.NEVER}.
|
|
||||||
* It assumes that it will be used in combination with service layer transactions
|
|
||||||
* that handle the flushing: the active transaction manager will temporarily change
|
|
||||||
* the flush mode to {@code FlushMode.AUTO} during a read-write transaction,
|
|
||||||
* with the flush mode reset to {@code FlushMode.NEVER} at the end of each
|
|
||||||
* transaction. If you intend to use this interceptor without transactions, consider
|
|
||||||
* changing the default flush mode (through the
|
|
||||||
* {@link #setFlushMode(int) "flushMode"} property).
|
|
||||||
*
|
|
||||||
* <p>In contrast to {@link OpenSessionInViewFilter}, this interceptor is
|
|
||||||
* configured in a Spring application context and can thus take advantage of bean
|
|
||||||
* wiring. It inherits common Hibernate configuration properties from
|
|
||||||
* {@link org.springframework.orm.hibernate3.HibernateAccessor},
|
|
||||||
* to be configured in a bean definition.
|
|
||||||
*
|
|
||||||
* <p><b>WARNING:</b> Applying this interceptor to existing logic can cause issues
|
|
||||||
* that have not appeared before, through the use of a single Hibernate
|
|
||||||
* {@code Session} for the processing of an entire request. In particular, the
|
|
||||||
* reassociation of persistent objects with a Hibernate {@code Session} has to
|
|
||||||
* occur at the very beginning of request processing, to avoid clashes with already
|
|
||||||
* loaded instances of the same objects.
|
|
||||||
*
|
|
||||||
* <p>Alternatively, turn this interceptor into deferred close mode, by specifying
|
|
||||||
* "singleSession"="false": It will not use a single session per request then,
|
|
||||||
* but rather let each data access operation or transaction use its own session
|
|
||||||
* (as would be the case without Open Session in View). Each of those sessions will
|
|
||||||
* be registered for deferred close though, which will actually be processed at
|
|
||||||
* request completion.
|
|
||||||
*
|
|
||||||
* <p>A single session per request allows for the most efficient first-level caching,
|
|
||||||
* but can cause side effects, for example on {@code saveOrUpdate} or when
|
|
||||||
* continuing after a rolled-back transaction. The deferred close strategy is as safe
|
|
||||||
* as no Open Session in View in that respect, while still allowing for lazy loading
|
|
||||||
* in views (but not providing a first-level cache for the entire request).
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 1.2
|
|
||||||
* @see #setSingleSession
|
|
||||||
* @see #setFlushMode
|
|
||||||
* @see OpenSessionInViewFilter
|
|
||||||
* @see OpenSessionInterceptor
|
|
||||||
* @see org.springframework.orm.hibernate3.HibernateTransactionManager
|
|
||||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession
|
|
||||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
|
||||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class OpenSessionInViewInterceptor extends org.springframework.orm.hibernate3.HibernateAccessor implements AsyncWebRequestInterceptor {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Suffix that gets appended to the {@code SessionFactory}
|
|
||||||
* {@code toString()} representation for the "participate in existing
|
|
||||||
* session handling" request attribute.
|
|
||||||
* @see #getParticipateAttributeName
|
|
||||||
*/
|
|
||||||
public static final String PARTICIPATE_SUFFIX = ".PARTICIPATE";
|
|
||||||
|
|
||||||
|
|
||||||
private boolean singleSession = true;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@code OpenSessionInViewInterceptor},
|
|
||||||
* turning the default flushMode to {@code FLUSH_NEVER}.
|
|
||||||
* @see #setFlushMode
|
|
||||||
*/
|
|
||||||
public OpenSessionInViewInterceptor() {
|
|
||||||
setFlushMode(FLUSH_NEVER);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether to use a single session for each request. Default is "true".
|
|
||||||
* <p>If set to false, each data access operation or transaction will use
|
|
||||||
* its own session (like without Open Session in View). Each of those
|
|
||||||
* sessions will be registered for deferred close, though, actually
|
|
||||||
* processed at request completion.
|
|
||||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#initDeferredClose
|
|
||||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#processDeferredClose
|
|
||||||
*/
|
|
||||||
public void setSingleSession(boolean singleSession) {
|
|
||||||
this.singleSession = singleSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return whether to use a single session for each request.
|
|
||||||
*/
|
|
||||||
protected boolean isSingleSession() {
|
|
||||||
return singleSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open a new Hibernate {@code Session} according to the settings of this
|
|
||||||
* {@code HibernateAccessor} and bind it to the thread via the
|
|
||||||
* {@link TransactionSynchronizationManager}.
|
|
||||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void preHandle(WebRequest request) throws DataAccessException {
|
|
||||||
String participateAttributeName = getParticipateAttributeName();
|
|
||||||
|
|
||||||
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
|
|
||||||
if (asyncManager.hasConcurrentResult()) {
|
|
||||||
if (applySessionBindingInterceptor(asyncManager, participateAttributeName)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((isSingleSession() && TransactionSynchronizationManager.hasResource(getSessionFactory())) ||
|
|
||||||
org.springframework.orm.hibernate3.SessionFactoryUtils.isDeferredCloseActive(getSessionFactory())) {
|
|
||||||
// Do not modify the Session: just mark the request accordingly.
|
|
||||||
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
|
|
||||||
int newCount = (count != null ? count + 1 : 1);
|
|
||||||
request.setAttribute(getParticipateAttributeName(), newCount, WebRequest.SCOPE_REQUEST);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (isSingleSession()) {
|
|
||||||
// single session mode
|
|
||||||
logger.debug("Opening single Hibernate Session in OpenSessionInViewInterceptor");
|
|
||||||
Session session = org.springframework.orm.hibernate3.SessionFactoryUtils.getSession(
|
|
||||||
getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
|
|
||||||
applyFlushMode(session, false);
|
|
||||||
org.springframework.orm.hibernate3.SessionHolder sessionHolder = new org.springframework.orm.hibernate3.SessionHolder(session);
|
|
||||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
|
|
||||||
|
|
||||||
AsyncRequestInterceptor asyncRequestInterceptor =
|
|
||||||
new AsyncRequestInterceptor(getSessionFactory(), sessionHolder);
|
|
||||||
asyncManager.registerCallableInterceptor(participateAttributeName, asyncRequestInterceptor);
|
|
||||||
asyncManager.registerDeferredResultInterceptor(participateAttributeName, asyncRequestInterceptor);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// deferred close mode
|
|
||||||
org.springframework.orm.hibernate3.SessionFactoryUtils.initDeferredClose(getSessionFactory());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flush the Hibernate {@code Session} before view rendering, if necessary.
|
|
||||||
* <p>Note that this just applies in {@link #isSingleSession() single session mode}!
|
|
||||||
* <p>The default is {@code FLUSH_NEVER} to avoid this extra flushing,
|
|
||||||
* assuming that service layer transactions have flushed their changes on commit.
|
|
||||||
* @see #setFlushMode
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void postHandle(WebRequest request, ModelMap model) throws DataAccessException {
|
|
||||||
if (isSingleSession()) {
|
|
||||||
// Only potentially flush in single session mode.
|
|
||||||
org.springframework.orm.hibernate3.SessionHolder sessionHolder =
|
|
||||||
(org.springframework.orm.hibernate3.SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
|
|
||||||
logger.debug("Flushing single Hibernate Session in OpenSessionInViewInterceptor");
|
|
||||||
try {
|
|
||||||
flushIfNecessary(sessionHolder.getSession(), false);
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
throw convertHibernateAccessException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unbind the Hibernate {@code Session} from the thread and close it (in
|
|
||||||
* single session mode), or process deferred close for all sessions that have
|
|
||||||
* been opened during the current request (in deferred close mode).
|
|
||||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void afterCompletion(WebRequest request, Exception ex) throws DataAccessException {
|
|
||||||
if (!decrementParticipateCount(request)) {
|
|
||||||
if (isSingleSession()) {
|
|
||||||
// single session mode
|
|
||||||
org.springframework.orm.hibernate3.SessionHolder sessionHolder =
|
|
||||||
(org.springframework.orm.hibernate3.SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
|
||||||
logger.debug("Closing single Hibernate Session in OpenSessionInViewInterceptor");
|
|
||||||
org.springframework.orm.hibernate3.SessionFactoryUtils.closeSession(sessionHolder.getSession());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// deferred close mode
|
|
||||||
org.springframework.orm.hibernate3.SessionFactoryUtils.processDeferredClose(getSessionFactory());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterConcurrentHandlingStarted(WebRequest request) {
|
|
||||||
if (!decrementParticipateCount(request)) {
|
|
||||||
if (isSingleSession()) {
|
|
||||||
TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IllegalStateException("Deferred close mode is not supported with async requests.");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean decrementParticipateCount(WebRequest request) {
|
|
||||||
String participateAttributeName = getParticipateAttributeName();
|
|
||||||
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
|
|
||||||
if (count == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Do not modify the Session: just clear the marker.
|
|
||||||
if (count > 1) {
|
|
||||||
request.setAttribute(participateAttributeName, count - 1, WebRequest.SCOPE_REQUEST);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
request.removeAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the name of the request attribute that identifies that a request is
|
|
||||||
* already intercepted.
|
|
||||||
* <p>The default implementation takes the {@code toString()} representation
|
|
||||||
* of the {@code SessionFactory} instance and appends {@link #PARTICIPATE_SUFFIX}.
|
|
||||||
*/
|
|
||||||
protected String getParticipateAttributeName() {
|
|
||||||
return getSessionFactory().toString() + PARTICIPATE_SUFFIX;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean applySessionBindingInterceptor(WebAsyncManager asyncManager, String key) {
|
|
||||||
if (asyncManager.getCallableInterceptor(key) == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,120 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2014 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3.support;
|
|
||||||
|
|
||||||
import org.aopalliance.intercept.MethodInterceptor;
|
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
|
||||||
import org.hibernate.FlushMode;
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
import org.springframework.dao.DataAccessResourceFailureException;
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple AOP Alliance {@link MethodInterceptor} implementation that binds a new
|
|
||||||
* Hibernate {@link Session} for each method invocation, if none bound before.
|
|
||||||
*
|
|
||||||
* <p>This is a simple Hibernate Session scoping interceptor along the lines of
|
|
||||||
* {@link OpenSessionInViewInterceptor}, just for use with AOP setup instead of
|
|
||||||
* MVC setup. It opens a new {@link Session} with flush mode "MANUAL" since the
|
|
||||||
* Session is only meant for reading, except when participating in a transaction.
|
|
||||||
*
|
|
||||||
* <p>Note: This can serve as a streamlined alternative to the outdated
|
|
||||||
* {@link org.springframework.orm.hibernate3.HibernateInterceptor}, providing
|
|
||||||
* plain Session binding without any automatic exception translation or the like.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 4.0.2
|
|
||||||
* @see OpenSessionInViewInterceptor
|
|
||||||
* @see OpenSessionInViewFilter
|
|
||||||
* @see org.springframework.orm.hibernate3.HibernateTransactionManager
|
|
||||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
|
||||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class OpenSessionInterceptor implements MethodInterceptor, InitializingBean {
|
|
||||||
|
|
||||||
private SessionFactory sessionFactory;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Hibernate SessionFactory that should be used to create Hibernate Sessions.
|
|
||||||
*/
|
|
||||||
public void setSessionFactory(SessionFactory sessionFactory) {
|
|
||||||
this.sessionFactory = sessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the Hibernate SessionFactory that should be used to create Hibernate Sessions.
|
|
||||||
*/
|
|
||||||
public SessionFactory getSessionFactory() {
|
|
||||||
return this.sessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterPropertiesSet() {
|
|
||||||
if (getSessionFactory() == null) {
|
|
||||||
throw new IllegalArgumentException("Property 'sessionFactory' is required");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
|
||||||
SessionFactory sf = getSessionFactory();
|
|
||||||
if (!TransactionSynchronizationManager.hasResource(sf)) {
|
|
||||||
// New Session to be bound for the current method's scope...
|
|
||||||
Session session = openSession();
|
|
||||||
try {
|
|
||||||
TransactionSynchronizationManager.bindResource(sf, new org.springframework.orm.hibernate3.SessionHolder(session));
|
|
||||||
return invocation.proceed();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
org.springframework.orm.hibernate3.SessionFactoryUtils.closeSession(session);
|
|
||||||
TransactionSynchronizationManager.unbindResource(sf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Pre-bound Session found -> simply proceed.
|
|
||||||
return invocation.proceed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open a Session for the SessionFactory that this interceptor uses.
|
|
||||||
* <p>The default implementation delegates to the {@link SessionFactory#openSession}
|
|
||||||
* method and sets the {@link Session}'s flush mode to "MANUAL".
|
|
||||||
* @return the Session to use
|
|
||||||
* @throws DataAccessResourceFailureException if the Session could not be created
|
|
||||||
* @see org.hibernate.FlushMode#MANUAL
|
|
||||||
*/
|
|
||||||
protected Session openSession() throws DataAccessResourceFailureException {
|
|
||||||
try {
|
|
||||||
Session session = getSessionFactory().openSession();
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
catch (HibernateException ex) {
|
|
||||||
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3.support;
|
|
||||||
|
|
||||||
import org.hibernate.EmptyInterceptor;
|
|
||||||
|
|
||||||
import org.springframework.aop.scope.ScopedObject;
|
|
||||||
import org.springframework.aop.support.AopUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hibernate3 interceptor used for getting the proper entity name for scoped
|
|
||||||
* beans. As scoped bean classes are proxies generated at runtime, they are
|
|
||||||
* unrecognized by the persisting framework. Using this interceptor, the
|
|
||||||
* original scoped bean class is retrieved end exposed to Hibernate for
|
|
||||||
* persisting.
|
|
||||||
*
|
|
||||||
* <p>Usage example:
|
|
||||||
*
|
|
||||||
* <pre class="code">
|
|
||||||
* <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
|
|
||||||
* ...
|
|
||||||
* <property name="entityInterceptor">
|
|
||||||
* <bean class="org.springframework.orm.hibernate3.support.ScopedBeanInterceptor"/>
|
|
||||||
* </property>
|
|
||||||
* </bean></pre>
|
|
||||||
*
|
|
||||||
* @author Costin Leau
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 2.0
|
|
||||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class ScopedBeanInterceptor extends EmptyInterceptor {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getEntityName(Object entity) {
|
|
||||||
if (entity instanceof ScopedObject) {
|
|
||||||
// Determine underlying object's type.
|
|
||||||
Object targetObject = ((ScopedObject) entity).getTargetObject();
|
|
||||||
return AopUtils.getTargetClass(targetObject).getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Any other object: delegate to the default implementation.
|
|
||||||
return super.getEntityName(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
/**
|
|
||||||
* Classes supporting the {@code org.springframework.orm.hibernate3} package.
|
|
||||||
* Contains a DAO base class for HibernateTemplate usage.
|
|
||||||
*/
|
|
||||||
package org.springframework.orm.hibernate3.support;
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue