ConfigurableJtaPlatform.java 5.4 KB
Newer Older
1
/*
2
 * Copyright 2002-2014 the original author or authors.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * 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;

19
import java.lang.reflect.InvocationHandler;
20
import java.lang.reflect.InvocationTargetException;
21 22 23 24 25 26
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;
27
import javax.transaction.TransactionManager;
28
import javax.transaction.TransactionSynchronizationRegistry;
29 30
import javax.transaction.UserTransaction;

31 32
import org.hibernate.TransactionException;
import org.hibernate.service.Service;
33 34 35

import org.springframework.transaction.jta.UserTransactionAdapter;
import org.springframework.util.Assert;
36
import org.springframework.util.ClassUtils;
37 38

/**
39 40 41
 * 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.
42 43 44 45
 *
 * @author Juergen Hoeller
 * @since 3.1.2
 */
46 47 48 49 50 51 52 53 54
@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
55 56
			jpClass = ClassUtils.forName("org.hibernate.service.jta.platform.spi.JtaPlatform",
					ConfigurableJtaPlatform.class.getClassLoader());
57 58 59 60
		}
		catch (ClassNotFoundException ex) {
			try {
				// Try Hibernate 4.3 JtaPlatform variant
61 62
				jpClass = ClassUtils.forName("org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform",
						ConfigurableJtaPlatform.class.getClassLoader());
63 64 65 66 67 68 69 70 71 72 73 74 75
			}
			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());
	}

76 77 78 79 80

	private final TransactionManager transactionManager;

	private final UserTransaction userTransaction;

81 82
	private final TransactionSynchronizationRegistry transactionSynchronizationRegistry;

83 84 85 86 87 88

	/**
	 * 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)
89
	 * @param tsr the JTA 1.1 TransactionSynchronizationRegistry (optional)
90
	 */
91
	public ConfigurableJtaPlatform(TransactionManager tm, UserTransaction ut, TransactionSynchronizationRegistry tsr) {
92 93 94
		Assert.notNull(tm, "TransactionManager reference must not be null");
		this.transactionManager = tm;
		this.userTransaction = (ut != null ? ut : new UserTransactionAdapter(tm));
95
		this.transactionSynchronizationRegistry = tsr;
96 97 98
	}


99
	public TransactionManager retrieveTransactionManager() {
100 101 102
		return this.transactionManager;
	}

103
	public UserTransaction retrieveUserTransaction() {
104 105 106
		return this.userTransaction;
	}

107 108
	public Object getTransactionIdentifier(Transaction transaction) {
		return transaction;
109 110
	}

111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
	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();
	}


139
	@Override
140
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
141 142 143 144 145 146 147 148 149
		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);
		}
150 151 152 153 154 155 156 157 158
	}

	/**
	 * 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);
159 160 161
	}

}