Jakarta EE 9 migration

Upgrades many dependency declarations; removes old EJB 2.x support and outdated Servlet-based integrations (Commons FileUpload, FreeMarker JSP support, Tiles).

Closes gh-22093
Closes gh-25354
Closes gh-26185
Closes gh-27423
See gh-27424
This commit is contained in:
Juergen Hoeller
2021-09-17 09:14:07 +02:00
parent 5822f1bf85
commit d84ca2ba90
1291 changed files with 4992 additions and 25322 deletions

View File

@@ -1,45 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.jca.cci;
import javax.resource.ResourceException;
import org.springframework.dao.DataAccessResourceFailureException;
/**
* Exception thrown when the creating of a CCI Record failed
* for connector-internal reasons.
*
* @author Juergen Hoeller
* @since 1.2
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
@SuppressWarnings("serial")
public class CannotCreateRecordException extends DataAccessResourceFailureException {
/**
* Constructor for CannotCreateRecordException.
* @param msg message
* @param ex the root ResourceException cause
*/
public CannotCreateRecordException(String msg, ResourceException ex) {
super(msg, ex);
}
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.jca.cci;
import javax.resource.ResourceException;
import org.springframework.dao.DataAccessResourceFailureException;
/**
* Fatal exception thrown when we can't connect to an EIS using CCI.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
@SuppressWarnings("serial")
public class CannotGetCciConnectionException extends DataAccessResourceFailureException {
/**
* Constructor for CannotGetCciConnectionException.
* @param msg message
* @param ex the root ResourceException cause
*/
public CannotGetCciConnectionException(String msg, ResourceException ex) {
super(msg, ex);
}
}

View File

@@ -1,44 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.jca.cci;
import javax.resource.ResourceException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
/**
* Exception thrown when the connector doesn't support a specific CCI operation.
*
* @author Juergen Hoeller
* @since 1.2
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
@SuppressWarnings("serial")
public class CciOperationNotSupportedException extends InvalidDataAccessResourceUsageException {
/**
* Constructor for CciOperationNotSupportedException.
* @param msg message
* @param ex the root ResourceException cause
*/
public CciOperationNotSupportedException(String msg, ResourceException ex) {
super(msg, ex);
}
}

View File

@@ -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
*
* https://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.jca.cci;
import java.sql.SQLException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
/**
* Exception thrown when a ResultSet has been accessed in an invalid fashion.
* Such exceptions always have a {@code java.sql.SQLException} root cause.
*
* <p>This typically happens when an invalid ResultSet column index or name
* has been specified.
*
* @author Juergen Hoeller
* @since 1.2
* @see javax.resource.cci.ResultSet
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
@SuppressWarnings("serial")
public class InvalidResultSetAccessException extends InvalidDataAccessResourceUsageException {
/**
* Constructor for InvalidResultSetAccessException.
* @param msg message
* @param ex the root cause
*/
public InvalidResultSetAccessException(String msg, SQLException ex) {
super(ex.getMessage(), ex);
}
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.jca.cci;
import javax.resource.ResourceException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
/**
* Exception thrown when the creating of a CCI Record failed because
* the connector doesn't support the desired CCI Record type.
*
* @author Juergen Hoeller
* @since 1.2
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
@SuppressWarnings("serial")
public class RecordTypeNotSupportedException extends InvalidDataAccessResourceUsageException {
/**
* Constructor for RecordTypeNotSupportedException.
* @param msg message
* @param ex the root ResourceException cause
*/
public RecordTypeNotSupportedException(String msg, ResourceException ex) {
super(msg, ex);
}
}

View File

@@ -1,297 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.jca.cci.connection;
import javax.resource.NotSupportedException;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.spi.LocalTransactionException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
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;
import org.springframework.util.Assert;
/**
* {@link org.springframework.transaction.PlatformTransactionManager} implementation
* that manages local transactions for a single CCI ConnectionFactory.
* Binds a CCI Connection from the specified ConnectionFactory to the thread,
* potentially allowing for one thread-bound Connection per ConnectionFactory.
*
* <p>Application code is required to retrieve the CCI Connection via
* {@link ConnectionFactoryUtils#getConnection(ConnectionFactory)} instead of a standard
* Java EE-style {@link ConnectionFactory#getConnection()} call. Spring classes such as
* {@link org.springframework.jca.cci.core.CciTemplate} use this strategy implicitly.
* If not used in combination with this transaction manager, the
* {@link ConnectionFactoryUtils} lookup strategy behaves exactly like the native
* DataSource lookup; it can thus be used in a portable fashion.
*
* <p>Alternatively, you can allow application code to work with the standard
* Java EE lookup pattern {@link ConnectionFactory#getConnection()}, for example
* for legacy code that is not aware of Spring at all. In that case, define a
* {@link TransactionAwareConnectionFactoryProxy} for your target ConnectionFactory,
* which will automatically participate in Spring-managed transactions.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see ConnectionFactoryUtils#getConnection(javax.resource.cci.ConnectionFactory)
* @see ConnectionFactoryUtils#releaseConnection
* @see TransactionAwareConnectionFactoryProxy
* @see org.springframework.jca.cci.core.CciTemplate
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
@SuppressWarnings("serial")
public class CciLocalTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
@Nullable
private ConnectionFactory connectionFactory;
/**
* Create a new CciLocalTransactionManager instance.
* A ConnectionFactory has to be set to be able to use it.
* @see #setConnectionFactory
*/
public CciLocalTransactionManager() {
}
/**
* Create a new CciLocalTransactionManager instance.
* @param connectionFactory the CCI ConnectionFactory to manage local transactions for
*/
public CciLocalTransactionManager(ConnectionFactory connectionFactory) {
setConnectionFactory(connectionFactory);
afterPropertiesSet();
}
/**
* Set the CCI ConnectionFactory that this instance should manage local
* transactions for.
*/
public void setConnectionFactory(@Nullable ConnectionFactory cf) {
if (cf instanceof TransactionAwareConnectionFactoryProxy) {
// If we got a TransactionAwareConnectionFactoryProxy, we need to perform transactions
// for its underlying target ConnectionFactory, else JMS access code won't see
// properly exposed transactions (i.e. transactions for the target ConnectionFactory).
this.connectionFactory = ((TransactionAwareConnectionFactoryProxy) cf).getTargetConnectionFactory();
}
else {
this.connectionFactory = cf;
}
}
/**
* Return the CCI ConnectionFactory that this instance manages local
* transactions for.
*/
@Nullable
public ConnectionFactory getConnectionFactory() {
return this.connectionFactory;
}
private ConnectionFactory obtainConnectionFactory() {
ConnectionFactory connectionFactory = getConnectionFactory();
Assert.state(connectionFactory != null, "No ConnectionFactory set");
return connectionFactory;
}
@Override
public void afterPropertiesSet() {
if (getConnectionFactory() == null) {
throw new IllegalArgumentException("Property 'connectionFactory' is required");
}
}
@Override
public Object getResourceFactory() {
return obtainConnectionFactory();
}
@Override
protected Object doGetTransaction() {
CciLocalTransactionObject txObject = new CciLocalTransactionObject();
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainConnectionFactory());
txObject.setConnectionHolder(conHolder);
return txObject;
}
@Override
protected boolean isExistingTransaction(Object transaction) {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction;
// Consider a pre-bound connection as transaction.
return txObject.hasConnectionHolder();
}
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction;
ConnectionFactory connectionFactory = obtainConnectionFactory();
Connection con = null;
try {
con = connectionFactory.getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + con + "] for local CCI transaction");
}
ConnectionHolder connectionHolder = new ConnectionHolder(con);
connectionHolder.setSynchronizedWithTransaction(true);
con.getLocalTransaction().begin();
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
connectionHolder.setTimeoutInSeconds(timeout);
}
txObject.setConnectionHolder(connectionHolder);
TransactionSynchronizationManager.bindResource(connectionFactory, connectionHolder);
}
catch (NotSupportedException ex) {
ConnectionFactoryUtils.releaseConnection(con, connectionFactory);
throw new CannotCreateTransactionException("CCI Connection does not support local transactions", ex);
}
catch (LocalTransactionException ex) {
ConnectionFactoryUtils.releaseConnection(con, connectionFactory);
throw new CannotCreateTransactionException("Could not begin local CCI transaction", ex);
}
catch (Throwable ex) {
ConnectionFactoryUtils.releaseConnection(con, connectionFactory);
throw new TransactionSystemException("Unexpected failure on begin of CCI local transaction", ex);
}
}
@Override
protected Object doSuspend(Object transaction) {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction;
txObject.setConnectionHolder(null);
return TransactionSynchronizationManager.unbindResource(obtainConnectionFactory());
}
@Override
protected void doResume(@Nullable Object transaction, Object suspendedResources) {
ConnectionHolder conHolder = (ConnectionHolder) suspendedResources;
TransactionSynchronizationManager.bindResource(obtainConnectionFactory(), conHolder);
}
protected boolean isRollbackOnly(Object transaction) throws TransactionException {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction;
return txObject.getConnectionHolder().isRollbackOnly();
}
@Override
protected void doCommit(DefaultTransactionStatus status) {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Committing CCI local transaction on Connection [" + con + "]");
}
try {
con.getLocalTransaction().commit();
}
catch (LocalTransactionException ex) {
throw new TransactionSystemException("Could not commit CCI local transaction", ex);
}
catch (ResourceException ex) {
throw new TransactionSystemException("Unexpected failure on commit of CCI local transaction", ex);
}
}
@Override
protected void doRollback(DefaultTransactionStatus status) {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Rolling back CCI local transaction on Connection [" + con + "]");
}
try {
con.getLocalTransaction().rollback();
}
catch (LocalTransactionException ex) {
throw new TransactionSystemException("Could not roll back CCI local transaction", ex);
}
catch (ResourceException ex) {
throw new TransactionSystemException("Unexpected failure on rollback of CCI local transaction", ex);
}
}
@Override
protected void doSetRollbackOnly(DefaultTransactionStatus status) {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) status.getTransaction();
if (status.isDebug()) {
logger.debug("Setting CCI local transaction [" + txObject.getConnectionHolder().getConnection() +
"] rollback-only");
}
txObject.getConnectionHolder().setRollbackOnly();
}
@Override
protected void doCleanupAfterCompletion(Object transaction) {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction;
ConnectionFactory connectionFactory = obtainConnectionFactory();
// Remove the connection holder from the thread.
TransactionSynchronizationManager.unbindResource(connectionFactory);
txObject.getConnectionHolder().clear();
Connection con = txObject.getConnectionHolder().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Releasing CCI Connection [" + con + "] after transaction");
}
ConnectionFactoryUtils.releaseConnection(con, connectionFactory);
}
/**
* CCI local transaction object, representing a ConnectionHolder.
* Used as transaction object by CciLocalTransactionManager.
* @see ConnectionHolder
*/
private static class CciLocalTransactionObject {
@Nullable
private ConnectionHolder connectionHolder;
public void setConnectionHolder(@Nullable ConnectionHolder connectionHolder) {
this.connectionHolder = connectionHolder;
}
public ConnectionHolder getConnectionHolder() {
Assert.state(this.connectionHolder != null, "No ConnectionHolder available");
return this.connectionHolder;
}
public boolean hasConnectionHolder() {
return (this.connectionHolder != null);
}
}
}

View File

@@ -1,220 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.jca.cci.connection;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.ConnectionSpec;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.transaction.support.ResourceHolderSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
/**
* Helper class that provides static methods for obtaining CCI Connections
* from a {@link javax.resource.cci.ConnectionFactory}. Includes special
* support for Spring-managed transactional Connections, e.g. managed
* by {@link CciLocalTransactionManager} or
* {@link org.springframework.transaction.jta.JtaTransactionManager}.
*
* <p>Used internally by {@link org.springframework.jca.cci.core.CciTemplate},
* Spring's CCI operation objects and the {@link CciLocalTransactionManager}.
* Can also be used directly in application code.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see #getConnection
* @see #releaseConnection
* @see CciLocalTransactionManager
* @see org.springframework.transaction.jta.JtaTransactionManager
* @see org.springframework.transaction.support.TransactionSynchronizationManager
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
public abstract class ConnectionFactoryUtils {
private static final Log logger = LogFactory.getLog(ConnectionFactoryUtils.class);
/**
* Obtain a Connection from the given ConnectionFactory. Translates ResourceExceptions
* into the Spring hierarchy of unchecked generic data access exceptions, simplifying
* calling code and making any exception that is thrown more meaningful.
* <p>Is aware of a corresponding Connection bound to the current thread, for example
* when using {@link CciLocalTransactionManager}. Will bind a Connection to the thread
* if transaction synchronization is active (e.g. if in a JTA transaction).
* @param cf the ConnectionFactory to obtain Connection from
* @return a CCI Connection from the given ConnectionFactory
* @throws org.springframework.jca.cci.CannotGetCciConnectionException
* if the attempt to get a Connection failed
* @see #releaseConnection
*/
public static Connection getConnection(ConnectionFactory cf)
throws org.springframework.jca.cci.CannotGetCciConnectionException {
return getConnection(cf, null);
}
/**
* Obtain a Connection from the given ConnectionFactory. Translates ResourceExceptions
* into the Spring hierarchy of unchecked generic data access exceptions, simplifying
* calling code and making any exception that is thrown more meaningful.
* <p>Is aware of a corresponding Connection bound to the current thread, for example
* when using {@link CciLocalTransactionManager}. Will bind a Connection to the thread
* if transaction synchronization is active (e.g. if in a JTA transaction).
* @param cf the ConnectionFactory to obtain Connection from
* @param spec the ConnectionSpec for the desired Connection (may be {@code null}).
* Note: If this is specified, a new Connection will be obtained for every call,
* without participating in a shared transactional Connection.
* @return a CCI Connection from the given ConnectionFactory
* @throws org.springframework.jca.cci.CannotGetCciConnectionException
* if the attempt to get a Connection failed
* @see #releaseConnection
*/
public static Connection getConnection(ConnectionFactory cf, @Nullable ConnectionSpec spec)
throws org.springframework.jca.cci.CannotGetCciConnectionException {
try {
if (spec != null) {
Assert.notNull(cf, "No ConnectionFactory specified");
return cf.getConnection(spec);
}
else {
return doGetConnection(cf);
}
}
catch (ResourceException ex) {
throw new org.springframework.jca.cci.CannotGetCciConnectionException("Could not get CCI Connection", ex);
}
}
/**
* Actually obtain a CCI Connection from the given ConnectionFactory.
* Same as {@link #getConnection}, but throwing the original ResourceException.
* <p>Is aware of a corresponding Connection bound to the current thread, for example
* when using {@link CciLocalTransactionManager}. Will bind a Connection to the thread
* if transaction synchronization is active (e.g. if in a JTA transaction).
* <p>Directly accessed by {@link TransactionAwareConnectionFactoryProxy}.
* @param cf the ConnectionFactory to obtain Connection from
* @return a CCI Connection from the given ConnectionFactory
* @throws ResourceException if thrown by CCI API methods
* @see #doReleaseConnection
*/
public static Connection doGetConnection(ConnectionFactory cf) throws ResourceException {
Assert.notNull(cf, "No ConnectionFactory specified");
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(cf);
if (conHolder != null) {
return conHolder.getConnection();
}
logger.debug("Opening CCI Connection");
Connection con = cf.getConnection();
if (TransactionSynchronizationManager.isSynchronizationActive()) {
conHolder = new ConnectionHolder(con);
conHolder.setSynchronizedWithTransaction(true);
TransactionSynchronizationManager.registerSynchronization(new ConnectionSynchronization(conHolder, cf));
TransactionSynchronizationManager.bindResource(cf, conHolder);
}
return con;
}
/**
* Determine whether the given JCA CCI Connection is transactional, that is,
* bound to the current thread by Spring's transaction facilities.
* @param con the Connection to check
* @param cf the ConnectionFactory that the Connection was obtained from
* (may be {@code null})
* @return whether the Connection is transactional
*/
public static boolean isConnectionTransactional(Connection con, @Nullable ConnectionFactory cf) {
if (cf == null) {
return false;
}
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(cf);
return (conHolder != null && conHolder.getConnection() == con);
}
/**
* Close the given Connection, obtained from the given ConnectionFactory,
* if it is not managed externally (that is, not bound to the thread).
* @param con the Connection to close if necessary
* (if this is {@code null}, the call will be ignored)
* @param cf the ConnectionFactory that the Connection was obtained from
* (can be {@code null})
* @see #getConnection
*/
public static void releaseConnection(@Nullable Connection con, @Nullable ConnectionFactory cf) {
try {
doReleaseConnection(con, cf);
}
catch (ResourceException ex) {
logger.debug("Could not close CCI Connection", ex);
}
catch (Throwable ex) {
// We don't trust the CCI driver: It might throw RuntimeException or Error.
logger.debug("Unexpected exception on closing CCI Connection", ex);
}
}
/**
* Actually close the given Connection, obtained from the given ConnectionFactory.
* Same as {@link #releaseConnection}, but throwing the original ResourceException.
* <p>Directly accessed by {@link TransactionAwareConnectionFactoryProxy}.
* @param con the Connection to close if necessary
* (if this is {@code null}, the call will be ignored)
* @param cf the ConnectionFactory that the Connection was obtained from
* (can be {@code null})
* @throws ResourceException if thrown by JCA CCI methods
* @see #doGetConnection
*/
public static void doReleaseConnection(@Nullable Connection con, @Nullable ConnectionFactory cf)
throws ResourceException {
if (con == null || isConnectionTransactional(con, cf)) {
return;
}
con.close();
}
/**
* Callback for resource cleanup at the end of a non-native CCI transaction
* (e.g. when participating in a JTA transaction).
*/
private static class ConnectionSynchronization
extends ResourceHolderSynchronization<ConnectionHolder, ConnectionFactory> {
public ConnectionSynchronization(ConnectionHolder connectionHolder, ConnectionFactory connectionFactory) {
super(connectionHolder, connectionFactory);
}
@Override
protected void releaseResource(ConnectionHolder resourceHolder, ConnectionFactory resourceKey) {
releaseConnection(resourceHolder.getConnection(), resourceKey);
}
}
}

View File

@@ -1,53 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.jca.cci.connection;
import javax.resource.cci.Connection;
import org.springframework.transaction.support.ResourceHolderSupport;
/**
* Resource holder wrapping a CCI {@link Connection}.
* {@link CciLocalTransactionManager} binds instances of this class to the thread,
* for a given {@link javax.resource.cci.ConnectionFactory}.
*
* <p>Note: This is an SPI class, not intended to be used by applications.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see CciLocalTransactionManager
* @see ConnectionFactoryUtils
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
public class ConnectionHolder extends ResourceHolderSupport {
private final Connection connection;
public ConnectionHolder(Connection connection) {
this.connection = connection;
}
public Connection getConnection() {
return this.connection;
}
}

View File

@@ -1,144 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.jca.cci.connection;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.ConnectionSpec;
import org.springframework.core.NamedThreadLocal;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* An adapter for a target CCI {@link javax.resource.cci.ConnectionFactory},
* applying the given ConnectionSpec to every standard {@code getConnection()}
* call, that is, implicitly invoking {@code getConnection(ConnectionSpec)}
* on the target. All other methods simply delegate to the corresponding methods
* of the target ConnectionFactory.
*
* <p>Can be used to proxy a target JNDI ConnectionFactory that does not have a
* ConnectionSpec configured. Client code can work with the ConnectionFactory
* without passing in a ConnectionSpec on every {@code getConnection()} call.
*
* <p>In the following example, client code can simply transparently work with
* the preconfigured "myConnectionFactory", implicitly accessing
* "myTargetConnectionFactory" with the specified user credentials.
*
* <pre class="code">
* &lt;bean id="myTargetConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean"&gt;
* &lt;property name="jndiName" value="java:comp/env/cci/mycf"/&gt;
* &lt;/bean>
*
* &lt;bean id="myConnectionFactory" class="org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter"&gt;
* &lt;property name="targetConnectionFactory" ref="myTargetConnectionFactory"/&gt;
* &lt;property name="connectionSpec"&gt;
* &lt;bean class="your.resource.adapter.ConnectionSpecImpl"&gt;
* &lt;property name="username" value="myusername"/&gt;
* &lt;property name="password" value="mypassword"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;/bean&gt;</pre>
*
* <p>If the "connectionSpec" is empty, this proxy will simply delegate to the
* standard {@code getConnection()} method of the target ConnectionFactory.
* This can be used to keep a UserCredentialsConnectionFactoryAdapter bean definition
* just for the <i>option</i> of implicitly passing in a ConnectionSpec if the
* particular target ConnectionFactory requires it.
*
* @author Juergen Hoeller
* @since 1.2
* @see #getConnection
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
@SuppressWarnings("serial")
public class ConnectionSpecConnectionFactoryAdapter extends DelegatingConnectionFactory {
@Nullable
private ConnectionSpec connectionSpec;
private final ThreadLocal<ConnectionSpec> threadBoundSpec =
new NamedThreadLocal<>("Current CCI ConnectionSpec");
/**
* Set the ConnectionSpec that this adapter should use for retrieving Connections.
* Default is none.
*/
public void setConnectionSpec(ConnectionSpec connectionSpec) {
this.connectionSpec = connectionSpec;
}
/**
* Set a ConnectionSpec for this proxy and the current thread.
* The given ConnectionSpec will be applied to all subsequent
* {@code getConnection()} calls on this ConnectionFactory proxy.
* <p>This will override any statically specified "connectionSpec" property.
* @param spec the ConnectionSpec to apply
* @see #removeConnectionSpecFromCurrentThread
*/
public void setConnectionSpecForCurrentThread(ConnectionSpec spec) {
this.threadBoundSpec.set(spec);
}
/**
* Remove any ConnectionSpec for this proxy from the current thread.
* A statically specified ConnectionSpec applies again afterwards.
* @see #setConnectionSpecForCurrentThread
*/
public void removeConnectionSpecFromCurrentThread() {
this.threadBoundSpec.remove();
}
/**
* Determine whether there is currently a thread-bound ConnectionSpec,
* using it if available, falling back to the statically specified
* "connectionSpec" property else.
* @see #doGetConnection
*/
@Override
public final Connection getConnection() throws ResourceException {
ConnectionSpec threadSpec = this.threadBoundSpec.get();
if (threadSpec != null) {
return doGetConnection(threadSpec);
}
else {
return doGetConnection(this.connectionSpec);
}
}
/**
* This implementation delegates to the {@code getConnection(ConnectionSpec)}
* method of the target ConnectionFactory, passing in the specified user credentials.
* If the specified username is empty, it will simply delegate to the standard
* {@code getConnection()} method of the target ConnectionFactory.
* @param spec the ConnectionSpec to apply
* @return the Connection
* @see javax.resource.cci.ConnectionFactory#getConnection(javax.resource.cci.ConnectionSpec)
* @see javax.resource.cci.ConnectionFactory#getConnection()
*/
protected Connection doGetConnection(@Nullable ConnectionSpec spec) throws ResourceException {
ConnectionFactory connectionFactory = getTargetConnectionFactory();
Assert.state(connectionFactory != null, "No 'targetConnectionFactory' set");
return (spec != null ? connectionFactory.getConnection(spec) : connectionFactory.getConnection());
}
}

View File

@@ -1,118 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.jca.cci.connection;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.ConnectionSpec;
import javax.resource.cci.RecordFactory;
import javax.resource.cci.ResourceAdapterMetaData;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* CCI {@link ConnectionFactory} implementation that delegates all calls
* to a given target {@link ConnectionFactory}.
*
* <p>This class is meant to be subclassed, with subclasses overriding only
* those methods (such as {@link #getConnection()}) that should not simply
* delegate to the target {@link ConnectionFactory}.
*
* @author Juergen Hoeller
* @since 1.2
* @see #getConnection
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
@SuppressWarnings("serial")
public class DelegatingConnectionFactory implements ConnectionFactory, InitializingBean {
@Nullable
private ConnectionFactory targetConnectionFactory;
/**
* Set the target ConnectionFactory that this ConnectionFactory should delegate to.
*/
public void setTargetConnectionFactory(@Nullable ConnectionFactory targetConnectionFactory) {
this.targetConnectionFactory = targetConnectionFactory;
}
/**
* Return the target ConnectionFactory that this ConnectionFactory should delegate to.
*/
@Nullable
public ConnectionFactory getTargetConnectionFactory() {
return this.targetConnectionFactory;
}
/**
* Obtain the target {@code ConnectionFactory} for actual use (never {@code null}).
* @since 5.0
*/
protected ConnectionFactory obtainTargetConnectionFactory() {
ConnectionFactory connectionFactory = getTargetConnectionFactory();
Assert.state(connectionFactory != null, "No 'targetConnectionFactory' set");
return connectionFactory;
}
@Override
public void afterPropertiesSet() {
if (getTargetConnectionFactory() == null) {
throw new IllegalArgumentException("Property 'targetConnectionFactory' is required");
}
}
@Override
public Connection getConnection() throws ResourceException {
return obtainTargetConnectionFactory().getConnection();
}
@Override
public Connection getConnection(ConnectionSpec connectionSpec) throws ResourceException {
return obtainTargetConnectionFactory().getConnection(connectionSpec);
}
@Override
public RecordFactory getRecordFactory() throws ResourceException {
return obtainTargetConnectionFactory().getRecordFactory();
}
@Override
public ResourceAdapterMetaData getMetaData() throws ResourceException {
return obtainTargetConnectionFactory().getMetaData();
}
@Override
public Reference getReference() throws NamingException {
return obtainTargetConnectionFactory().getReference();
}
@Override
public void setReference(Reference reference) {
obtainTargetConnectionFactory().setReference(reference);
}
}

View File

@@ -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
*
* https://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.jca.cci.connection;
import javax.resource.NotSupportedException;
import javax.resource.ResourceException;
import javax.resource.cci.IndexedRecord;
import javax.resource.cci.MappedRecord;
import javax.resource.cci.RecordFactory;
/**
* Implementation of the CCI RecordFactory interface that always throws
* NotSupportedException.
*
* <p>Useful as a placeholder for a RecordFactory argument (for example as
* defined by the RecordCreator callback), in particular when the connector's
* {@code ConnectionFactory.getRecordFactory()} implementation happens to
* throw NotSupportedException early rather than throwing the exception from
* RecordFactory's methods.
*
* @author Juergen Hoeller
* @since 1.2.4
* @see org.springframework.jca.cci.core.RecordCreator#createRecord(javax.resource.cci.RecordFactory)
* @see org.springframework.jca.cci.core.CciTemplate#getRecordFactory(javax.resource.cci.ConnectionFactory)
* @see javax.resource.cci.ConnectionFactory#getRecordFactory()
* @see javax.resource.NotSupportedException
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
public class NotSupportedRecordFactory implements RecordFactory {
@Override
public MappedRecord createMappedRecord(String name) throws ResourceException {
throw new NotSupportedException("The RecordFactory facility is not supported by the connector");
}
@Override
public IndexedRecord createIndexedRecord(String name) throws ResourceException {
throw new NotSupportedException("The RecordFactory facility is not supported by the connector");
}
}

View File

@@ -1,264 +0,0 @@
/*
* Copyright 2002-2020 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
*
* https://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.jca.cci.connection;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.resource.NotSupportedException;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.ConnectionSpec;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* A CCI ConnectionFactory adapter that returns the same Connection on all
* {@code getConnection} calls, and ignores calls to
* {@code Connection.close()}.
*
* <p>Useful for testing and standalone environments, to keep using the same
* Connection for multiple CciTemplate calls, without having a pooling
* ConnectionFactory, also spanning any number of transactions.
*
* <p>You can either pass in a CCI Connection directly, or let this
* factory lazily create a Connection via a given target ConnectionFactory.
*
* @author Juergen Hoeller
* @since 1.2
* @see #getConnection()
* @see javax.resource.cci.Connection#close()
* @see org.springframework.jca.cci.core.CciTemplate
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
@SuppressWarnings("serial")
public class SingleConnectionFactory extends DelegatingConnectionFactory implements DisposableBean {
protected final Log logger = LogFactory.getLog(getClass());
/** Wrapped Connection. */
@Nullable
private Connection target;
/** Proxy Connection. */
@Nullable
private Connection connection;
/** Synchronization monitor for the shared Connection. */
private final Object connectionMonitor = new Object();
/**
* Create a new SingleConnectionFactory for bean-style usage.
* @see #setTargetConnectionFactory
*/
public SingleConnectionFactory() {
}
/**
* Create a new SingleConnectionFactory that always returns the
* given Connection.
* @param target the single Connection
*/
public SingleConnectionFactory(Connection target) {
Assert.notNull(target, "Target Connection must not be null");
this.target = target;
this.connection = getCloseSuppressingConnectionProxy(target);
}
/**
* Create a new SingleConnectionFactory that always returns a single
* Connection which it will lazily create via the given target
* ConnectionFactory.
* @param targetConnectionFactory the target ConnectionFactory
*/
public SingleConnectionFactory(ConnectionFactory targetConnectionFactory) {
Assert.notNull(targetConnectionFactory, "Target ConnectionFactory must not be null");
setTargetConnectionFactory(targetConnectionFactory);
}
/**
* Make sure a Connection or ConnectionFactory has been set.
*/
@Override
public void afterPropertiesSet() {
if (this.connection == null && getTargetConnectionFactory() == null) {
throw new IllegalArgumentException("Connection or 'targetConnectionFactory' is required");
}
}
@Override
public Connection getConnection() throws ResourceException {
synchronized (this.connectionMonitor) {
if (this.connection == null) {
initConnection();
}
return this.connection;
}
}
@Override
public Connection getConnection(ConnectionSpec connectionSpec) throws ResourceException {
throw new NotSupportedException(
"SingleConnectionFactory does not support custom ConnectionSpec");
}
/**
* Close the underlying Connection.
* The provider of this ConnectionFactory needs to care for proper shutdown.
* <p>As this bean implements DisposableBean, a bean factory will
* automatically invoke this on destruction of its cached singletons.
*/
@Override
public void destroy() {
resetConnection();
}
/**
* Initialize the single underlying Connection.
* <p>Closes and reinitializes the Connection if an underlying
* Connection is present already.
* @throws javax.resource.ResourceException if thrown by CCI API methods
*/
public void initConnection() throws ResourceException {
if (getTargetConnectionFactory() == null) {
throw new IllegalStateException(
"'targetConnectionFactory' is required for lazily initializing a Connection");
}
synchronized (this.connectionMonitor) {
if (this.target != null) {
closeConnection(this.target);
}
this.target = doCreateConnection();
prepareConnection(this.target);
if (logger.isDebugEnabled()) {
logger.debug("Established shared CCI Connection: " + this.target);
}
this.connection = getCloseSuppressingConnectionProxy(this.target);
}
}
/**
* Reset the underlying shared Connection, to be reinitialized on next access.
*/
public void resetConnection() {
synchronized (this.connectionMonitor) {
if (this.target != null) {
closeConnection(this.target);
}
this.target = null;
this.connection = null;
}
}
/**
* Create a CCI Connection via this template's ConnectionFactory.
* @return the new CCI Connection
* @throws javax.resource.ResourceException if thrown by CCI API methods
*/
protected Connection doCreateConnection() throws ResourceException {
ConnectionFactory connectionFactory = getTargetConnectionFactory();
Assert.state(connectionFactory != null, "No 'targetConnectionFactory' set");
return connectionFactory.getConnection();
}
/**
* Prepare the given Connection before it is exposed.
* <p>The default implementation is empty. Can be overridden in subclasses.
* @param con the Connection to prepare
*/
protected void prepareConnection(Connection con) throws ResourceException {
}
/**
* Close the given Connection.
* @param con the Connection to close
*/
protected void closeConnection(Connection con) {
try {
con.close();
}
catch (Throwable ex) {
logger.warn("Could not close shared CCI Connection", ex);
}
}
/**
* Wrap the given Connection with a proxy that delegates every method call to it
* but suppresses close calls. This is useful for allowing application code to
* handle a special framework Connection just like an ordinary Connection from a
* CCI ConnectionFactory.
* @param target the original Connection to wrap
* @return the wrapped Connection
*/
protected Connection getCloseSuppressingConnectionProxy(Connection target) {
return (Connection) Proxy.newProxyInstance(
Connection.class.getClassLoader(),
new Class<?>[] {Connection.class},
new CloseSuppressingInvocationHandler(target));
}
/**
* Invocation handler that suppresses close calls on CCI Connections.
*/
private static final class CloseSuppressingInvocationHandler implements InvocationHandler {
private final Connection target;
private CloseSuppressingInvocationHandler(Connection target) {
this.target = target;
}
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
switch (method.getName()) {
case "equals":
// Only consider equal when proxies are identical.
return (proxy == args[0]);
case "hashCode":
// Use hashCode of Connection proxy.
return System.identityHashCode(proxy);
case "close":
// Handle close method: don't pass the call on.
return null;
}
try {
return method.invoke(this.target, args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
}

View File

@@ -1,171 +0,0 @@
/*
* Copyright 2002-2020 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
*
* https://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.jca.cci.connection;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import org.springframework.lang.Nullable;
/**
* Proxy for a target CCI {@link javax.resource.cci.ConnectionFactory}, adding
* awareness of Spring-managed transactions. Similar to a transactional JNDI
* ConnectionFactory as provided by a Java EE server.
*
* <p>Data access code that should remain unaware of Spring's data access support
* can work with this proxy to seamlessly participate in Spring-managed transactions.
* Note that the transaction manager, for example the {@link CciLocalTransactionManager},
* still needs to work with underlying ConnectionFactory, <i>not</i> with this proxy.
*
* <p><b>Make sure that TransactionAwareConnectionFactoryProxy is the outermost
* ConnectionFactory of a chain of ConnectionFactory proxies/adapters.</b>
* TransactionAwareConnectionFactoryProxy can delegate either directly to the
* target connection pool or to some intermediate proxy/adapter like
* {@link ConnectionSpecConnectionFactoryAdapter}.
*
* <p>Delegates to {@link ConnectionFactoryUtils} for automatically participating in
* thread-bound transactions, for example managed by {@link CciLocalTransactionManager}.
* {@code getConnection} calls and {@code close} calls on returned Connections
* will behave properly within a transaction, i.e. always operate on the transactional
* Connection. If not within a transaction, normal ConnectionFactory behavior applies.
*
* <p>This proxy allows data access code to work with the plain JCA CCI API and still
* participate in Spring-managed transactions, similar to CCI code in a Java EE/JTA
* environment. However, if possible, use Spring's ConnectionFactoryUtils, CciTemplate or
* CCI operation objects to get transaction participation even without a proxy for
* the target ConnectionFactory, avoiding the need to define such a proxy in the first place.
*
* <p><b>NOTE:</b> This ConnectionFactory proxy needs to return wrapped Connections
* in order to handle close calls properly. Therefore, the returned Connections cannot
* be cast to a native CCI Connection type or to a connection pool implementation type.
*
* @author Juergen Hoeller
* @since 1.2
* @see javax.resource.cci.ConnectionFactory#getConnection
* @see javax.resource.cci.Connection#close
* @see ConnectionFactoryUtils#doGetConnection
* @see ConnectionFactoryUtils#doReleaseConnection
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
@SuppressWarnings("serial")
public class TransactionAwareConnectionFactoryProxy extends DelegatingConnectionFactory {
/**
* Create a new TransactionAwareConnectionFactoryProxy.
* @see #setTargetConnectionFactory
*/
public TransactionAwareConnectionFactoryProxy() {
}
/**
* Create a new TransactionAwareConnectionFactoryProxy.
* @param targetConnectionFactory the target ConnectionFactory
*/
public TransactionAwareConnectionFactoryProxy(ConnectionFactory targetConnectionFactory) {
setTargetConnectionFactory(targetConnectionFactory);
afterPropertiesSet();
}
/**
* Delegate to ConnectionFactoryUtils for automatically participating in Spring-managed
* transactions. Throws the original ResourceException, if any.
* @return a transactional Connection if any, a new one else
* @see org.springframework.jca.cci.connection.ConnectionFactoryUtils#doGetConnection
*/
@Override
public Connection getConnection() throws ResourceException {
ConnectionFactory targetConnectionFactory = obtainTargetConnectionFactory();
Connection con = ConnectionFactoryUtils.doGetConnection(targetConnectionFactory);
return getTransactionAwareConnectionProxy(con, targetConnectionFactory);
}
/**
* Wrap the given Connection with a proxy that delegates every method call to it
* but delegates {@code close} calls to ConnectionFactoryUtils.
* @param target the original Connection to wrap
* @param cf the ConnectionFactory that the Connection came from
* @return the wrapped Connection
* @see javax.resource.cci.Connection#close()
* @see ConnectionFactoryUtils#doReleaseConnection
*/
protected Connection getTransactionAwareConnectionProxy(Connection target, ConnectionFactory cf) {
return (Connection) Proxy.newProxyInstance(
Connection.class.getClassLoader(),
new Class<?>[] {Connection.class},
new TransactionAwareInvocationHandler(target, cf));
}
/**
* Invocation handler that delegates close calls on CCI Connections
* to ConnectionFactoryUtils for being aware of thread-bound transactions.
*/
private static class TransactionAwareInvocationHandler implements InvocationHandler {
private final Connection target;
private final ConnectionFactory connectionFactory;
public TransactionAwareInvocationHandler(Connection target, ConnectionFactory cf) {
this.target = target;
this.connectionFactory = cf;
}
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Invocation on Connection interface coming in...
switch (method.getName()) {
case "equals":
// Only consider equal when proxies are identical.
return (proxy == args[0]);
case "hashCode":
// Use hashCode of Connection proxy.
return System.identityHashCode(proxy);
case "getLocalTransaction":
if (ConnectionFactoryUtils.isConnectionTransactional(this.target, this.connectionFactory)) {
throw new javax.resource.spi.IllegalStateException(
"Local transaction handling not allowed within a managed transaction");
}
return this.target.getLocalTransaction();
case "close":
// Handle close method: only close if not within a transaction.
ConnectionFactoryUtils.doReleaseConnection(this.target, this.connectionFactory);
return null;
}
// Invoke method on target Connection.
try {
return method.invoke(this.target, args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
}

View File

@@ -1,11 +0,0 @@
/**
* Provides a utility class for easy ConnectionFactory access,
* a PlatformTransactionManager for local CCI transactions,
* and various simple ConnectionFactory proxies/adapters.
*/
@NonNullApi
@NonNullFields
package org.springframework.jca.cci.connection;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -1,130 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.jca.cci.core;
import javax.resource.cci.InteractionSpec;
import javax.resource.cci.Record;
import org.springframework.dao.DataAccessException;
import org.springframework.lang.Nullable;
/**
* Interface that specifies a basic set of CCI operations on an EIS.
* Implemented by CciTemplate. Not often used, but a useful option
* to enhance testability, as it can easily be mocked or stubbed.
*
* <p>Alternatively, the standard CCI infrastructure can be mocked.
* However, mocking this interface constitutes significantly less work.
*
* @author Juergen Hoeller
* @since 1.2
* @see CciTemplate
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
public interface CciOperations {
/**
* Execute a request on an EIS with CCI, implemented as callback action
* working on a CCI Connection. This allows for implementing arbitrary
* data access operations, within Spring's managed CCI environment:
* that is, participating in Spring-managed transactions and converting
* JCA ResourceExceptions into Spring's DataAccessException hierarchy.
* <p>The callback action can return a result object, for example a
* domain object or a collection of domain objects.
* @param action the callback object that specifies the action
* @return the result object returned by the action, if any
* @throws DataAccessException if there is any problem
*/
@Nullable
<T> T execute(ConnectionCallback<T> action) throws DataAccessException;
/**
* Execute a request on an EIS with CCI, implemented as callback action
* working on a CCI Interaction. This allows for implementing arbitrary
* data access operations on a single Interaction, within Spring's managed
* CCI environment: that is, participating in Spring-managed transactions
* and converting JCA ResourceExceptions into Spring's DataAccessException
* hierarchy.
* <p>The callback action can return a result object, for example a
* domain object or a collection of domain objects.
* @param action the callback object that specifies the action
* @return the result object returned by the action, if any
* @throws DataAccessException if there is any problem
*/
@Nullable
<T> T execute(InteractionCallback<T> action) throws DataAccessException;
/**
* Execute the specified interaction on an EIS with CCI.
* @param spec the CCI InteractionSpec instance that defines
* the interaction (connector-specific)
* @param inputRecord the input record
* @return the output record
* @throws DataAccessException if there is any problem
*/
@Nullable
Record execute(InteractionSpec spec, Record inputRecord) throws DataAccessException;
/**
* Execute the specified interaction on an EIS with CCI.
* @param spec the CCI InteractionSpec instance that defines
* the interaction (connector-specific)
* @param inputRecord the input record
* @param outputRecord the output record
* @throws DataAccessException if there is any problem
*/
void execute(InteractionSpec spec, Record inputRecord, Record outputRecord) throws DataAccessException;
/**
* Execute the specified interaction on an EIS with CCI.
* @param spec the CCI InteractionSpec instance that defines
* the interaction (connector-specific)
* @param inputCreator object that creates the input record to use
* @return the output record
* @throws DataAccessException if there is any problem
*/
Record execute(InteractionSpec spec, RecordCreator inputCreator) throws DataAccessException;
/**
* Execute the specified interaction on an EIS with CCI.
* @param spec the CCI InteractionSpec instance that defines
* the interaction (connector-specific)
* @param inputRecord the input record
* @param outputExtractor object to convert the output record to a result object
* @return the output data extracted with the RecordExtractor object
* @throws DataAccessException if there is any problem
*/
@Nullable
<T> T execute(InteractionSpec spec, Record inputRecord, RecordExtractor<T> outputExtractor)
throws DataAccessException;
/**
* Execute the specified interaction on an EIS with CCI.
* @param spec the CCI InteractionSpec instance that defines
* the interaction (connector-specific)
* @param inputCreator object that creates the input record to use
* @param outputExtractor object to convert the output record to a result object
* @return the output data extracted with the RecordExtractor object
* @throws DataAccessException if there is any problem
*/
@Nullable
<T> T execute(InteractionSpec spec, RecordCreator inputCreator, RecordExtractor<T> outputExtractor)
throws DataAccessException;
}

View File

@@ -1,461 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.jca.cci.core;
import java.sql.SQLException;
import javax.resource.NotSupportedException;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.ConnectionSpec;
import javax.resource.cci.IndexedRecord;
import javax.resource.cci.Interaction;
import javax.resource.cci.InteractionSpec;
import javax.resource.cci.MappedRecord;
import javax.resource.cci.Record;
import javax.resource.cci.RecordFactory;
import javax.resource.cci.ResultSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* <b>This is the central class in the CCI core package.</b>
* It simplifies the use of CCI and helps to avoid common errors.
* It executes core CCI workflow, leaving application code to provide parameters
* to CCI and extract results. This class executes EIS queries or updates,
* catching ResourceExceptions and translating them to the generic exception
* hierarchy defined in the {@code org.springframework.dao} package.
*
* <p>Code using this class can pass in and receive {@link javax.resource.cci.Record}
* instances, or alternatively implement callback interfaces for creating input
* Records and extracting result objects from output Records (or CCI ResultSets).
*
* <p>Can be used within a service implementation via direct instantiation
* with a ConnectionFactory reference, or get prepared in an application context
* and given to services as bean reference. Note: The ConnectionFactory should
* always be configured as a bean in the application context, in the first case
* given to the service directly, in the second case to the prepared template.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see RecordCreator
* @see RecordExtractor
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
public class CciTemplate implements CciOperations {
private final Log logger = LogFactory.getLog(getClass());
@Nullable
private ConnectionFactory connectionFactory;
@Nullable
private ConnectionSpec connectionSpec;
@Nullable
private RecordCreator outputRecordCreator;
/**
* Construct a new CciTemplate for bean usage.
* <p>Note: The ConnectionFactory has to be set before using the instance.
* @see #setConnectionFactory
*/
public CciTemplate() {
}
/**
* Construct a new CciTemplate, given a ConnectionFactory to obtain Connections from.
* Note: This will trigger eager initialization of the exception translator.
* @param connectionFactory the JCA ConnectionFactory to obtain Connections from
*/
public CciTemplate(ConnectionFactory connectionFactory) {
setConnectionFactory(connectionFactory);
afterPropertiesSet();
}
/**
* Construct a new CciTemplate, given a ConnectionFactory to obtain Connections from.
* Note: This will trigger eager initialization of the exception translator.
* @param connectionFactory the JCA ConnectionFactory to obtain Connections from
* @param connectionSpec the CCI ConnectionSpec to obtain Connections for
* (may be {@code null})
*/
public CciTemplate(ConnectionFactory connectionFactory, @Nullable ConnectionSpec connectionSpec) {
setConnectionFactory(connectionFactory);
if (connectionSpec != null) {
setConnectionSpec(connectionSpec);
}
afterPropertiesSet();
}
/**
* Set the CCI ConnectionFactory to obtain Connections from.
*/
public void setConnectionFactory(@Nullable ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
/**
* Return the CCI ConnectionFactory used by this template.
*/
@Nullable
public ConnectionFactory getConnectionFactory() {
return this.connectionFactory;
}
private ConnectionFactory obtainConnectionFactory() {
ConnectionFactory connectionFactory = getConnectionFactory();
Assert.state(connectionFactory != null, "No ConnectionFactory set");
return connectionFactory;
}
/**
* Set the CCI ConnectionSpec that this template instance is
* supposed to obtain Connections for.
*/
public void setConnectionSpec(@Nullable ConnectionSpec connectionSpec) {
this.connectionSpec = connectionSpec;
}
/**
* Return the CCI ConnectionSpec used by this template, if any.
*/
@Nullable
public ConnectionSpec getConnectionSpec() {
return this.connectionSpec;
}
/**
* Set a RecordCreator that should be used for creating default output Records.
* <p>Default is none: When no explicit output Record gets passed into an
* {@code execute} method, CCI's {@code Interaction.execute} variant
* that returns an output Record will be called.
* <p>Specify a RecordCreator here if you always need to call CCI's
* {@code Interaction.execute} variant with a passed-in output Record.
* Unless there is an explicitly specified output Record, CciTemplate will
* then invoke this RecordCreator to create a default output Record instance.
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record)
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record, Record)
*/
public void setOutputRecordCreator(@Nullable RecordCreator creator) {
this.outputRecordCreator = creator;
}
/**
* Return a RecordCreator that should be used for creating default output Records.
*/
@Nullable
public RecordCreator getOutputRecordCreator() {
return this.outputRecordCreator;
}
public void afterPropertiesSet() {
if (getConnectionFactory() == null) {
throw new IllegalArgumentException("Property 'connectionFactory' is required");
}
}
/**
* Create a template derived from this template instance,
* inheriting the ConnectionFactory and other settings but
* overriding the ConnectionSpec used for obtaining Connections.
* @param connectionSpec the CCI ConnectionSpec that the derived template
* instance is supposed to obtain Connections for
* @return the derived template instance
* @see #setConnectionSpec
*/
public CciTemplate getDerivedTemplate(ConnectionSpec connectionSpec) {
CciTemplate derived = new CciTemplate(obtainConnectionFactory(), connectionSpec);
RecordCreator recordCreator = getOutputRecordCreator();
if (recordCreator != null) {
derived.setOutputRecordCreator(recordCreator);
}
return derived;
}
@Override
@Nullable
public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
ConnectionFactory connectionFactory = obtainConnectionFactory();
Connection con = org.springframework.jca.cci.connection.ConnectionFactoryUtils.getConnection(
connectionFactory, getConnectionSpec());
try {
return action.doInConnection(con, connectionFactory);
}
catch (NotSupportedException ex) {
throw new org.springframework.jca.cci.CciOperationNotSupportedException(
"CCI operation not supported by connector", ex);
}
catch (ResourceException ex) {
throw new DataAccessResourceFailureException("CCI operation failed", ex);
}
catch (SQLException ex) {
throw new org.springframework.jca.cci.InvalidResultSetAccessException(
"Parsing of CCI ResultSet failed", ex);
}
finally {
org.springframework.jca.cci.connection.ConnectionFactoryUtils.releaseConnection(
con, getConnectionFactory());
}
}
@Override
@Nullable
public <T> T execute(final InteractionCallback<T> action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
return execute((ConnectionCallback<T>) (connection, connectionFactory) -> {
Interaction interaction = connection.createInteraction();
try {
return action.doInInteraction(interaction, connectionFactory);
}
finally {
closeInteraction(interaction);
}
});
}
@Override
@Nullable
public Record execute(InteractionSpec spec, Record inputRecord) throws DataAccessException {
return doExecute(spec, inputRecord, null, new SimpleRecordExtractor());
}
@Override
public void execute(InteractionSpec spec, Record inputRecord, Record outputRecord) throws DataAccessException {
doExecute(spec, inputRecord, outputRecord, null);
}
@Override
public Record execute(InteractionSpec spec, RecordCreator inputCreator) throws DataAccessException {
Record output = doExecute(spec, createRecord(inputCreator), null, new SimpleRecordExtractor());
Assert.state(output != null, "Invalid output record");
return output;
}
@Override
public <T> T execute(InteractionSpec spec, Record inputRecord, RecordExtractor<T> outputExtractor)
throws DataAccessException {
return doExecute(spec, inputRecord, null, outputExtractor);
}
@Override
public <T> T execute(InteractionSpec spec, RecordCreator inputCreator, RecordExtractor<T> outputExtractor)
throws DataAccessException {
return doExecute(spec, createRecord(inputCreator), null, outputExtractor);
}
/**
* Execute the specified interaction on an EIS with CCI.
* All other interaction execution methods go through this.
* @param spec the CCI InteractionSpec instance that defines
* the interaction (connector-specific)
* @param inputRecord the input record
* @param outputRecord output record (can be {@code null})
* @param outputExtractor object to convert the output record to a result object
* @return the output data extracted with the RecordExtractor object
* @throws DataAccessException if there is any problem
*/
@Nullable
protected <T> T doExecute(
final InteractionSpec spec, final Record inputRecord, @Nullable final Record outputRecord,
@Nullable final RecordExtractor<T> outputExtractor) throws DataAccessException {
return execute((InteractionCallback<T>) (interaction, connectionFactory) -> {
Record outputRecordToUse = outputRecord;
try {
if (outputRecord != null || getOutputRecordCreator() != null) {
// Use the CCI execute method with output record as parameter.
if (outputRecord == null) {
RecordFactory recordFactory = getRecordFactory(connectionFactory);
outputRecordToUse = getOutputRecordCreator().createRecord(recordFactory);
}
interaction.execute(spec, inputRecord, outputRecordToUse);
}
else {
outputRecordToUse = interaction.execute(spec, inputRecord);
}
return (outputExtractor != null ? outputExtractor.extractData(outputRecordToUse) : null);
}
finally {
if (outputRecordToUse instanceof ResultSet) {
closeResultSet((ResultSet) outputRecordToUse);
}
}
});
}
/**
* Create an indexed Record through the ConnectionFactory's RecordFactory.
* @param name the name of the record
* @return the Record
* @throws DataAccessException if creation of the Record failed
* @see #getRecordFactory(javax.resource.cci.ConnectionFactory)
* @see javax.resource.cci.RecordFactory#createIndexedRecord(String)
*/
public IndexedRecord createIndexedRecord(String name) throws DataAccessException {
try {
RecordFactory recordFactory = getRecordFactory(obtainConnectionFactory());
return recordFactory.createIndexedRecord(name);
}
catch (NotSupportedException ex) {
throw new org.springframework.jca.cci.RecordTypeNotSupportedException(
"Creation of indexed Record not supported by connector", ex);
}
catch (ResourceException ex) {
throw new org.springframework.jca.cci.CannotCreateRecordException(
"Creation of indexed Record failed", ex);
}
}
/**
* Create a mapped Record from the ConnectionFactory's RecordFactory.
* @param name record name
* @return the Record
* @throws DataAccessException if creation of the Record failed
* @see #getRecordFactory(javax.resource.cci.ConnectionFactory)
* @see javax.resource.cci.RecordFactory#createMappedRecord(String)
*/
public MappedRecord createMappedRecord(String name) throws DataAccessException {
try {
RecordFactory recordFactory = getRecordFactory(obtainConnectionFactory());
return recordFactory.createMappedRecord(name);
}
catch (NotSupportedException ex) {
throw new org.springframework.jca.cci.RecordTypeNotSupportedException(
"Creation of mapped Record not supported by connector", ex);
}
catch (ResourceException ex) {
throw new org.springframework.jca.cci.CannotCreateRecordException(
"Creation of mapped Record failed", ex);
}
}
/**
* Invoke the given RecordCreator, converting JCA ResourceExceptions
* to Spring's DataAccessException hierarchy.
* @param recordCreator the RecordCreator to invoke
* @return the created Record
* @throws DataAccessException if creation of the Record failed
* @see #getRecordFactory(javax.resource.cci.ConnectionFactory)
* @see RecordCreator#createRecord(javax.resource.cci.RecordFactory)
*/
protected Record createRecord(RecordCreator recordCreator) throws DataAccessException {
try {
RecordFactory recordFactory = getRecordFactory(obtainConnectionFactory());
return recordCreator.createRecord(recordFactory);
}
catch (NotSupportedException ex) {
throw new org.springframework.jca.cci.RecordTypeNotSupportedException(
"Creation of the desired Record type not supported by connector", ex);
}
catch (ResourceException ex) {
throw new org.springframework.jca.cci.CannotCreateRecordException(
"Creation of the desired Record failed", ex);
}
}
/**
* Return a RecordFactory for the given ConnectionFactory.
* <p>Default implementation returns the connector's RecordFactory if
* available, falling back to a NotSupportedRecordFactory placeholder.
* This allows to invoke a RecordCreator callback with a non-null
* RecordFactory reference in any case.
* @param connectionFactory the CCI ConnectionFactory
* @return the CCI RecordFactory for the ConnectionFactory
* @throws ResourceException if thrown by CCI methods
* @see org.springframework.jca.cci.connection.NotSupportedRecordFactory
*/
protected RecordFactory getRecordFactory(ConnectionFactory connectionFactory) throws ResourceException {
try {
return connectionFactory.getRecordFactory();
}
catch (NotSupportedException ex) {
return new org.springframework.jca.cci.connection.NotSupportedRecordFactory();
}
}
/**
* Close the given CCI Interaction and ignore any thrown exception.
* This is useful for typical finally blocks in manual CCI code.
* @param interaction the CCI Interaction to close
* @see javax.resource.cci.Interaction#close()
*/
private void closeInteraction(@Nullable Interaction interaction) {
if (interaction != null) {
try {
interaction.close();
}
catch (ResourceException ex) {
logger.trace("Could not close CCI Interaction", ex);
}
catch (Throwable ex) {
// We don't trust the CCI driver: It might throw RuntimeException or Error.
logger.trace("Unexpected exception on closing CCI Interaction", ex);
}
}
}
/**
* Close the given CCI ResultSet and ignore any thrown exception.
* This is useful for typical finally blocks in manual CCI code.
* @param resultSet the CCI ResultSet to close
* @see javax.resource.cci.ResultSet#close()
*/
private void closeResultSet(@Nullable ResultSet resultSet) {
if (resultSet != null) {
try {
resultSet.close();
}
catch (SQLException ex) {
logger.trace("Could not close CCI ResultSet", ex);
}
catch (Throwable ex) {
// We don't trust the CCI driver: It might throw RuntimeException or Error.
logger.trace("Unexpected exception on closing CCI ResultSet", ex);
}
}
}
private static class SimpleRecordExtractor implements RecordExtractor<Record> {
@Override
public Record extractData(Record record) {
return record;
}
}
}

View File

@@ -1,83 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.jca.cci.core;
import java.sql.SQLException;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.lang.Nullable;
/**
* Generic callback interface for code that operates on a CCI Connection.
* Allows to execute any number of operations on a single Connection,
* using any type and number of Interaction.
*
* <p>This is particularly useful for delegating to existing data access code
* that expects a Connection to work on and throws ResourceException. For newly
* written code, it is strongly recommended to use CciTemplate's more specific
* {@code execute} variants.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @param <T> the result type
* @see CciTemplate#execute(ConnectionCallback)
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, javax.resource.cci.Record)
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, RecordCreator, RecordExtractor)
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
@FunctionalInterface
public interface ConnectionCallback<T> {
/**
* Gets called by {@code CciTemplate.execute} with an active CCI Connection.
* Does not need to care about activating or closing the Connection, or handling
* transactions.
* <p>If called without a thread-bound CCI transaction (initiated by
* CciLocalTransactionManager), the code will simply get executed on the CCI
* Connection with its transactional semantics. If CciTemplate is configured
* to use a JTA-aware ConnectionFactory, the CCI 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. Note that there's special
* support for single step actions: see the {@code CciTemplate.execute}
* variants. A thrown RuntimeException is treated as application exception:
* it gets propagated to the caller of the template.
* @param connection active CCI Connection
* @param connectionFactory the CCI ConnectionFactory that the Connection was
* created with (gives access to RecordFactory and ResourceAdapterMetaData)
* @return a result object, or {@code null} if none
* @throws ResourceException if thrown by a CCI method, to be auto-converted
* to a DataAccessException
* @throws SQLException if thrown by a ResultSet method, to be auto-converted
* to a DataAccessException
* @throws DataAccessException in case of custom exceptions
* @see javax.resource.cci.ConnectionFactory#getRecordFactory()
* @see javax.resource.cci.ConnectionFactory#getMetaData()
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, RecordCreator, RecordExtractor)
*/
@Nullable
T doInConnection(Connection connection, ConnectionFactory connectionFactory)
throws ResourceException, SQLException, DataAccessException;
}

View File

@@ -1,84 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.jca.cci.core;
import java.sql.SQLException;
import javax.resource.ResourceException;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.Interaction;
import org.springframework.dao.DataAccessException;
import org.springframework.lang.Nullable;
/**
* Generic callback interface for code that operates on a CCI Interaction.
* Allows to execute any number of operations on a single Interaction, for
* example a single execute call or repeated execute calls with varying
* parameters.
*
* <p>This is particularly useful for delegating to existing data access code
* that expects an Interaction to work on and throws ResourceException. For newly
* written code, it is strongly recommended to use CciTemplate's more specific
* {@code execute} variants.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @param <T> the result type
* @see CciTemplate#execute(InteractionCallback)
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, javax.resource.cci.Record)
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, RecordCreator, RecordExtractor)
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
@FunctionalInterface
public interface InteractionCallback<T> {
/**
* Gets called by {@code CciTemplate.execute} with an active CCI Interaction.
* Does not need to care about activating or closing the Interaction, or
* handling transactions.
* <p>If called without a thread-bound CCI transaction (initiated by
* CciLocalTransactionManager), the code will simply get executed on the CCI
* Interaction with its transactional semantics. If CciTemplate is configured
* to use a JTA-aware ConnectionFactory, the CCI Interaction 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. Note that there's special
* support for single step actions: see the {@code CciTemplate.execute}
* variants. A thrown RuntimeException is treated as application exception:
* it gets propagated to the caller of the template.
* @param interaction active CCI Interaction
* @param connectionFactory the CCI ConnectionFactory that the Connection was
* created with (gives access to RecordFactory and ResourceAdapterMetaData)
* @return a result object, or {@code null} if none
* @throws ResourceException if thrown by a CCI method, to be auto-converted
* to a DataAccessException
* @throws SQLException if thrown by a ResultSet method, to be auto-converted
* to a DataAccessException
* @throws DataAccessException in case of custom exceptions
* @see javax.resource.cci.ConnectionFactory#getRecordFactory()
* @see javax.resource.cci.ConnectionFactory#getMetaData()
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, RecordCreator, RecordExtractor)
*/
@Nullable
T doInInteraction(Interaction interaction, ConnectionFactory connectionFactory)
throws ResourceException, SQLException, DataAccessException;
}

View File

@@ -1,68 +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
*
* https://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.jca.cci.core;
import javax.resource.ResourceException;
import javax.resource.cci.Record;
import javax.resource.cci.RecordFactory;
import org.springframework.dao.DataAccessException;
/**
* Callback interface for creating a CCI Record instance,
* usually based on the passed-in CCI RecordFactory.
*
* <p>Used for input Record creation in CciTemplate. Alternatively,
* Record instances can be passed into CciTemplate's corresponding
* {@code execute} methods directly, either instantiated manually
* or created through CciTemplate's Record factory methods.
*
* <P>Also used for creating default output Records in CciTemplate.
* This is useful when the JCA connector needs an explicit output Record
* instance, but no output Records should be passed into CciTemplate's
* {@code execute} methods.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, RecordCreator)
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, RecordCreator, RecordExtractor)
* @see CciTemplate#createIndexedRecord(String)
* @see CciTemplate#createMappedRecord(String)
* @see CciTemplate#setOutputRecordCreator(RecordCreator)
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
@FunctionalInterface
public interface RecordCreator {
/**
* Create a CCI Record instance, usually based on the passed-in CCI RecordFactory.
* <p>For use as <i>input</i> creator with CciTemplate's {@code execute} methods,
* this method should create a <i>populated</i> Record instance. For use as
* <i>output</i> Record creator, it should return an <i>empty</i> Record instance.
* @param recordFactory the CCI RecordFactory (never {@code null}, but not guaranteed to be
* supported by the connector: its create methods might throw NotSupportedException)
* @return the Record instance
* @throws ResourceException if thrown by a CCI method, to be auto-converted
* to a DataAccessException
* @throws DataAccessException in case of custom exceptions
*/
Record createRecord(RecordFactory recordFactory) throws ResourceException, DataAccessException;
}

View File

@@ -1,70 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.jca.cci.core;
import java.sql.SQLException;
import javax.resource.ResourceException;
import javax.resource.cci.Record;
import org.springframework.dao.DataAccessException;
import org.springframework.lang.Nullable;
/**
* Callback interface for extracting a result object from a CCI Record instance.
*
* <p>Used for output object creation in CciTemplate. Alternatively, output
* Records can also be returned to client code as-is. In case of a CCI ResultSet
* as execution result, you will almost always want to implement a RecordExtractor,
* to be able to read the ResultSet in a managed fashion, with the CCI Connection
* still open while reading the ResultSet.
*
* <p>Implementations of this interface perform the actual work of extracting
* results, but don't need to worry about exception handling. ResourceExceptions
* will be caught and handled correctly by the CciTemplate class.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @param <T> the result type
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, Record, RecordExtractor)
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, RecordCreator, RecordExtractor)
* @see javax.resource.cci.ResultSet
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
@FunctionalInterface
public interface RecordExtractor<T> {
/**
* Process the data in the given Record, creating a corresponding result object.
* @param record the Record to extract data from
* (possibly a CCI ResultSet)
* @return an arbitrary result object, or {@code null} if none
* (the extractor will typically be stateful in the latter case)
* @throws ResourceException if thrown by a CCI method, to be auto-converted
* to a DataAccessException
* @throws SQLException if thrown by a ResultSet method, to be auto-converted
* to a DataAccessException
* @throws DataAccessException in case of custom exceptions
* @see javax.resource.cci.ResultSet
*/
@Nullable
T extractData(Record record) throws ResourceException, SQLException, DataAccessException;
}

View File

@@ -1,10 +0,0 @@
/**
* Provides the core JCA CCI support, based on CciTemplate
* and its associated callback interfaces.
*/
@NonNullApi
@NonNullFields
package org.springframework.jca.cci.core;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -1,147 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.jca.cci.core.support;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.ConnectionSpec;
import org.springframework.dao.support.DaoSupport;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Convenient super class for CCI-based data access objects.
*
* <p>Requires a {@link javax.resource.cci.ConnectionFactory} to be set,
* providing a {@link org.springframework.jca.cci.core.CciTemplate} based
* on it to subclasses through the {@link #getCciTemplate()} method.
*
* <p>This base class is mainly intended for CciTemplate usage but can
* also be used when working with a Connection directly or when using
* {@code org.springframework.jca.cci.object} classes.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see #setConnectionFactory
* @see #getCciTemplate
* @see org.springframework.jca.cci.core.CciTemplate
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
public abstract class CciDaoSupport extends DaoSupport {
@Nullable
private org.springframework.jca.cci.core.CciTemplate cciTemplate;
/**
* Set the ConnectionFactory to be used by this DAO.
*/
public final void setConnectionFactory(ConnectionFactory connectionFactory) {
if (this.cciTemplate == null || connectionFactory != this.cciTemplate.getConnectionFactory()) {
this.cciTemplate = createCciTemplate(connectionFactory);
}
}
/**
* Create a CciTemplate for the given ConnectionFactory.
* Only invoked if populating the DAO with a ConnectionFactory reference!
* <p>Can be overridden in subclasses to provide a CciTemplate instance
* with different configuration, or a custom CciTemplate subclass.
* @param connectionFactory the CCI ConnectionFactory to create a CciTemplate for
* @return the new CciTemplate instance
* @see #setConnectionFactory(javax.resource.cci.ConnectionFactory)
*/
protected org.springframework.jca.cci.core.CciTemplate createCciTemplate(ConnectionFactory connectionFactory) {
return new org.springframework.jca.cci.core.CciTemplate(connectionFactory);
}
/**
* Return the ConnectionFactory used by this DAO.
*/
@Nullable
public final ConnectionFactory getConnectionFactory() {
return (this.cciTemplate != null ? this.cciTemplate.getConnectionFactory() : null);
}
/**
* Set the CciTemplate for this DAO explicitly,
* as an alternative to specifying a ConnectionFactory.
*/
public final void setCciTemplate(org.springframework.jca.cci.core.CciTemplate cciTemplate) {
this.cciTemplate = cciTemplate;
}
/**
* Return the CciTemplate for this DAO,
* pre-initialized with the ConnectionFactory or set explicitly.
*/
@Nullable
public final org.springframework.jca.cci.core.CciTemplate getCciTemplate() {
return this.cciTemplate;
}
@Override
protected final void checkDaoConfig() {
if (this.cciTemplate == null) {
throw new IllegalArgumentException("'connectionFactory' or 'cciTemplate' is required");
}
}
/**
* Obtain a CciTemplate derived from the main template instance,
* inheriting the ConnectionFactory and other settings but
* overriding the ConnectionSpec used for obtaining Connections.
* @param connectionSpec the CCI ConnectionSpec that the returned
* template instance is supposed to obtain Connections for
* @return the derived template instance
* @see org.springframework.jca.cci.core.CciTemplate#getDerivedTemplate(javax.resource.cci.ConnectionSpec)
*/
protected final org.springframework.jca.cci.core.CciTemplate getCciTemplate(ConnectionSpec connectionSpec) {
org.springframework.jca.cci.core.CciTemplate cciTemplate = getCciTemplate();
Assert.state(cciTemplate != null, "No CciTemplate set");
return cciTemplate.getDerivedTemplate(connectionSpec);
}
/**
* Get a CCI Connection, either from the current transaction or a new one.
* @return the CCI Connection
* @throws org.springframework.jca.cci.CannotGetCciConnectionException
* if the attempt to get a Connection failed
* @see org.springframework.jca.cci.connection.ConnectionFactoryUtils#getConnection(javax.resource.cci.ConnectionFactory)
*/
protected final Connection getConnection() throws org.springframework.jca.cci.CannotGetCciConnectionException {
ConnectionFactory connectionFactory = getConnectionFactory();
Assert.state(connectionFactory != null, "No ConnectionFactory set");
return org.springframework.jca.cci.connection.ConnectionFactoryUtils.getConnection(connectionFactory);
}
/**
* Close the given CCI Connection, created via this bean's ConnectionFactory,
* if it isn't bound to the thread.
* @param con the Connection to close
* @see org.springframework.jca.cci.connection.ConnectionFactoryUtils#releaseConnection
*/
protected final void releaseConnection(Connection con) {
org.springframework.jca.cci.connection.ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory());
}
}

View File

@@ -1,107 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.jca.cci.core.support;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.resource.cci.Record;
import javax.resource.cci.Streamable;
import org.springframework.util.FileCopyUtils;
/**
* CCI Record implementation for a COMMAREA, holding a byte array.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see org.springframework.jca.cci.object.MappingCommAreaOperation
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
@SuppressWarnings("serial")
public class CommAreaRecord implements Record, Streamable {
private byte[] bytes = new byte[0];
private String recordName = "";
private String recordShortDescription = "";
/**
* Create a new CommAreaRecord.
* @see #read(java.io.InputStream)
*/
public CommAreaRecord() {
}
/**
* Create a new CommAreaRecord.
* @param bytes the bytes to fill the record with
*/
public CommAreaRecord(byte[] bytes) {
this.bytes = bytes;
}
@Override
public void setRecordName(String recordName) {
this.recordName = recordName;
}
@Override
public String getRecordName() {
return this.recordName;
}
@Override
public void setRecordShortDescription(String recordShortDescription) {
this.recordShortDescription = recordShortDescription;
}
@Override
public String getRecordShortDescription() {
return this.recordShortDescription;
}
@Override
public void read(InputStream in) throws IOException {
this.bytes = FileCopyUtils.copyToByteArray(in);
}
@Override
public void write(OutputStream out) throws IOException {
out.write(this.bytes);
out.flush();
}
public byte[] toByteArray() {
return this.bytes;
}
@Override
public Object clone() {
return new CommAreaRecord(this.bytes);
}
}

View File

@@ -1,10 +0,0 @@
/**
* Classes supporting the {@code org.springframework.jca.cci.core} package.
* Contains a DAO base class for CciTemplate usage.
*/
@NonNullApi
@NonNullFields
package org.springframework.jca.cci.core.support;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -1,99 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.jca.cci.object;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.InteractionSpec;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Base class for EIS operation objects that work with the CCI API.
* Encapsulates a CCI ConnectionFactory and a CCI InteractionSpec.
*
* <p>Works with a CciTemplate instance underneath. EIS operation objects
* are an alternative to working with a CciTemplate directly.
*
* @author Juergen Hoeller
* @since 1.2
* @see #setConnectionFactory
* @see #setInteractionSpec
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
public abstract class EisOperation implements InitializingBean {
private org.springframework.jca.cci.core.CciTemplate cciTemplate =
new org.springframework.jca.cci.core.CciTemplate();
@Nullable
private InteractionSpec interactionSpec;
/**
* Set the CciTemplate to be used by this operation.
* Alternatively, specify a CCI ConnectionFactory.
* @see #setConnectionFactory
*/
public void setCciTemplate(org.springframework.jca.cci.core.CciTemplate cciTemplate) {
Assert.notNull(cciTemplate, "CciTemplate must not be null");
this.cciTemplate = cciTemplate;
}
/**
* Return the CciTemplate used by this operation.
*/
public org.springframework.jca.cci.core.CciTemplate getCciTemplate() {
return this.cciTemplate;
}
/**
* Set the CCI ConnectionFactory to be used by this operation.
*/
public void setConnectionFactory(ConnectionFactory connectionFactory) {
this.cciTemplate.setConnectionFactory(connectionFactory);
}
/**
* Set the CCI InteractionSpec for this operation.
*/
public void setInteractionSpec(@Nullable InteractionSpec interactionSpec) {
this.interactionSpec = interactionSpec;
}
/**
* Return the CCI InteractionSpec for this operation.
*/
@Nullable
public InteractionSpec getInteractionSpec() {
return this.interactionSpec;
}
@Override
public void afterPropertiesSet() {
this.cciTemplate.afterPropertiesSet();
if (this.interactionSpec == null) {
throw new IllegalArgumentException("InteractionSpec is required");
}
}
}

View File

@@ -1,100 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.jca.cci.object;
import java.io.IOException;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.InteractionSpec;
import javax.resource.cci.Record;
import javax.resource.cci.RecordFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataRetrievalFailureException;
/**
* EIS operation object for access to COMMAREA records.
* Subclass of the generic MappingRecordOperation class.
*
* @author Thierry Templier
* @since 1.2
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
public abstract class MappingCommAreaOperation extends MappingRecordOperation {
/**
* Create a new MappingCommAreaQuery.
* @see #setConnectionFactory
* @see #setInteractionSpec
*/
public MappingCommAreaOperation() {
}
/**
* Create a new MappingCommAreaQuery.
* @param connectionFactory the ConnectionFactory to use to obtain connections
* @param interactionSpec specification to configure the interaction
*/
public MappingCommAreaOperation(ConnectionFactory connectionFactory, InteractionSpec interactionSpec) {
super(connectionFactory, interactionSpec);
}
@Override
protected final Record createInputRecord(RecordFactory recordFactory, Object inObject) {
try {
return new org.springframework.jca.cci.core.support.CommAreaRecord(objectToBytes(inObject));
}
catch (IOException ex) {
throw new DataRetrievalFailureException("I/O exception during bytes conversion", ex);
}
}
@Override
protected final Object extractOutputData(Record record) throws DataAccessException {
org.springframework.jca.cci.core.support.CommAreaRecord commAreaRecord =
(org.springframework.jca.cci.core.support.CommAreaRecord) record;
try {
return bytesToObject(commAreaRecord.toByteArray());
}
catch (IOException ex) {
throw new DataRetrievalFailureException("I/O exception during bytes conversion", ex);
}
}
/**
* Method used to convert an object into COMMAREA bytes.
* @param inObject the input data
* @return the COMMAREA's bytes
* @throws IOException if thrown by I/O methods
* @throws DataAccessException if conversion failed
*/
protected abstract byte[] objectToBytes(Object inObject) throws IOException, DataAccessException;
/**
* Method used to convert the COMMAREA's bytes to an object.
* @param bytes the COMMAREA's bytes
* @return the output data
* @throws IOException if thrown by I/O methods
* @throws DataAccessException if conversion failed
*/
protected abstract Object bytesToObject(byte[] bytes) throws IOException, DataAccessException;
}

View File

@@ -1,157 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.jca.cci.object;
import java.sql.SQLException;
import javax.resource.ResourceException;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.InteractionSpec;
import javax.resource.cci.Record;
import javax.resource.cci.RecordFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* EIS operation object that expects mapped input and output objects,
* converting to and from CCI Records.
*
* <p>Concrete subclasses must implement the abstract
* {@code createInputRecord(RecordFactory, Object)} and
* {@code extractOutputData(Record)} methods, to create an input
* Record from an object and to convert an output Record into an object,
* respectively.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see #createInputRecord(javax.resource.cci.RecordFactory, Object)
* @see #extractOutputData(javax.resource.cci.Record)
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
public abstract class MappingRecordOperation extends EisOperation {
/**
* Constructor that allows use as a JavaBean.
*/
public MappingRecordOperation() {
}
/**
* Convenient constructor with ConnectionFactory and specifications
* (connection and interaction).
* @param connectionFactory the ConnectionFactory to use to obtain connections
*/
public MappingRecordOperation(ConnectionFactory connectionFactory, InteractionSpec interactionSpec) {
getCciTemplate().setConnectionFactory(connectionFactory);
setInteractionSpec(interactionSpec);
}
/**
* Set a RecordCreator that should be used for creating default output Records.
* <p>Default is none: CCI's {@code Interaction.execute} variant
* that returns an output Record will be called.
* <p>Specify a RecordCreator here if you always need to call CCI's
* {@code Interaction.execute} variant with a passed-in output Record.
* This RecordCreator will then be invoked to create a default output Record instance.
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record)
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record, Record)
* @see org.springframework.jca.cci.core.CciTemplate#setOutputRecordCreator
*/
public void setOutputRecordCreator(org.springframework.jca.cci.core.RecordCreator creator) {
getCciTemplate().setOutputRecordCreator(creator);
}
/**
* Execute the interaction encapsulated by this operation object.
* @param inputObject the input data, to be converted to a Record
* by the {@code createInputRecord} method
* @return the output data extracted with the {@code extractOutputData} method
* @throws DataAccessException if there is any problem
* @see #createInputRecord
* @see #extractOutputData
*/
@Nullable
public Object execute(Object inputObject) throws DataAccessException {
InteractionSpec interactionSpec = getInteractionSpec();
Assert.state(interactionSpec != null, "No InteractionSpec set");
return getCciTemplate().execute(
interactionSpec, new RecordCreatorImpl(inputObject), new RecordExtractorImpl());
}
/**
* Subclasses must implement this method to generate an input Record
* from an input object passed into the {@code execute} method.
* @param inputObject the passed-in input object
* @return the CCI input Record
* @throws ResourceException if thrown by a CCI method, to be auto-converted
* to a DataAccessException
* @see #execute(Object)
*/
protected abstract Record createInputRecord(RecordFactory recordFactory, Object inputObject)
throws ResourceException, DataAccessException;
/**
* Subclasses must implement this method to convert the Record returned
* by CCI execution into a result object for the {@code execute} method.
* @param outputRecord the Record returned by CCI execution
* @return the result object
* @throws ResourceException if thrown by a CCI method, to be auto-converted
* to a DataAccessException
* @see #execute(Object)
*/
protected abstract Object extractOutputData(Record outputRecord)
throws ResourceException, SQLException, DataAccessException;
/**
* Implementation of RecordCreator that calls the enclosing
* class's {@code createInputRecord} method.
*/
protected class RecordCreatorImpl implements org.springframework.jca.cci.core.RecordCreator {
private final Object inputObject;
public RecordCreatorImpl(Object inObject) {
this.inputObject = inObject;
}
@Override
public Record createRecord(RecordFactory recordFactory) throws ResourceException, DataAccessException {
return createInputRecord(recordFactory, this.inputObject);
}
}
/**
* Implementation of RecordExtractor that calls the enclosing
* class's {@code extractOutputData} method.
*/
protected class RecordExtractorImpl implements org.springframework.jca.cci.core.RecordExtractor<Object> {
@Override
public Object extractData(Record record) throws ResourceException, SQLException, DataAccessException {
return extractOutputData(record);
}
}
}

View File

@@ -1,87 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.jca.cci.object;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.InteractionSpec;
import javax.resource.cci.Record;
import org.springframework.dao.DataAccessException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* EIS operation object that accepts a passed-in CCI input Record
* and returns a corresponding CCI output Record.
*
* @author Juergen Hoeller
* @since 1.2
* @deprecated as of 5.3, in favor of specific data access APIs
* (or native CCI usage if there is no alternative)
*/
@Deprecated
public class SimpleRecordOperation extends EisOperation {
/**
* Constructor that allows use as a JavaBean.
*/
public SimpleRecordOperation() {
}
/**
* Convenient constructor with ConnectionFactory and specifications
* (connection and interaction).
* @param connectionFactory the ConnectionFactory to use to obtain connections
*/
public SimpleRecordOperation(ConnectionFactory connectionFactory, InteractionSpec interactionSpec) {
getCciTemplate().setConnectionFactory(connectionFactory);
setInteractionSpec(interactionSpec);
}
/**
* Execute the CCI interaction encapsulated by this operation object.
* <p>This method will call CCI's {@code Interaction.execute} variant
* that returns an output Record.
* @param inputRecord the input record
* @return the output record
* @throws DataAccessException if there is any problem
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record)
*/
@Nullable
public Record execute(Record inputRecord) throws DataAccessException {
InteractionSpec interactionSpec = getInteractionSpec();
Assert.state(interactionSpec != null, "No InteractionSpec set");
return getCciTemplate().execute(interactionSpec, inputRecord);
}
/**
* Execute the CCI interaction encapsulated by this operation object.
* <p>This method will call CCI's {@code Interaction.execute} variant
* with a passed-in output Record.
* @param inputRecord the input record
* @param outputRecord the output record
* @throws DataAccessException if there is any problem
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record, Record)
*/
public void execute(Record inputRecord, Record outputRecord) throws DataAccessException {
InteractionSpec interactionSpec = getInteractionSpec();
Assert.state(interactionSpec != null, "No InteractionSpec set");
getCciTemplate().execute(interactionSpec, inputRecord, outputRecord);
}
}

View File

@@ -1,13 +0,0 @@
/**
* The classes in this package represent EIS operations as threadsafe,
* reusable objects. This higher level of CCI abstraction depends on the
* lower-level abstraction in the {@code org.springframework.jca.cci.core} package.
* Exceptions thrown are as in the {@code org.springframework.dao} package,
* meaning that code using this package does not need to worry about error handling.
*/
@NonNullApi
@NonNullFields
package org.springframework.jca.cci.object;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -1,12 +0,0 @@
/**
* This package contains Spring's support for the Common Client Interface (CCI),
* as defined by the J2EE Connector Architecture. It is conceptually similar
* to the {@code org.springframework.jdbc} package, providing the same
* levels of data access abstraction.
*/
@NonNullApi
@NonNullFields
package org.springframework.jca.cci;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -1,47 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.jca.context;
import javax.resource.spi.BootstrapContext;
import org.springframework.beans.factory.Aware;
/**
* Interface to be implemented by any object that wishes to be
* notified of the BootstrapContext (typically determined by the
* {@link ResourceAdapterApplicationContext}) that it runs in.
*
* @author Juergen Hoeller
* @author Chris Beams
* @since 2.5
* @see javax.resource.spi.BootstrapContext
*/
public interface BootstrapContextAware extends Aware {
/**
* Set the BootstrapContext that this object runs in.
* <p>Invoked after population of normal bean properties but before an init
* callback like InitializingBean's {@code afterPropertiesSet} or a
* custom init-method. Invoked after ApplicationContextAware's
* {@code setApplicationContext}.
* @param bootstrapContext the BootstrapContext object to be used by this object
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
* @see org.springframework.context.ApplicationContextAware#setApplicationContext
*/
void setBootstrapContext(BootstrapContext bootstrapContext);
}

View File

@@ -1,64 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.jca.context;
import javax.resource.spi.BootstrapContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.lang.Nullable;
/**
* {@link org.springframework.beans.factory.config.BeanPostProcessor}
* implementation that passes the BootstrapContext to beans that implement
* the {@link BootstrapContextAware} interface.
*
* <p>{@link ResourceAdapterApplicationContext} automatically registers
* this processor with its underlying bean factory.
*
* @author Juergen Hoeller
* @since 2.5
* @see BootstrapContextAware
*/
class BootstrapContextAwareProcessor implements BeanPostProcessor {
@Nullable
private final BootstrapContext bootstrapContext;
/**
* Create a new BootstrapContextAwareProcessor for the given context.
*/
public BootstrapContextAwareProcessor(@Nullable BootstrapContext bootstrapContext) {
this.bootstrapContext = bootstrapContext;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (this.bootstrapContext != null && bean instanceof BootstrapContextAware) {
((BootstrapContextAware) bean).setBootstrapContext(this.bootstrapContext);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}

View File

@@ -1,66 +0,0 @@
/*
* Copyright 2002-2017 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
*
* https://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.jca.context;
import javax.resource.spi.BootstrapContext;
import javax.resource.spi.work.WorkManager;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.util.Assert;
/**
* {@link org.springframework.context.ApplicationContext} implementation
* for a JCA ResourceAdapter. Needs to be initialized with the JCA
* {@link javax.resource.spi.BootstrapContext}, passing it on to
* Spring-managed beans that implement {@link BootstrapContextAware}.
*
* @author Juergen Hoeller
* @since 2.5
* @see SpringContextResourceAdapter
* @see BootstrapContextAware
*/
public class ResourceAdapterApplicationContext extends GenericApplicationContext {
private final BootstrapContext bootstrapContext;
/**
* Create a new ResourceAdapterApplicationContext for the given BootstrapContext.
* @param bootstrapContext the JCA BootstrapContext that the ResourceAdapter
* has been started with
*/
public ResourceAdapterApplicationContext(BootstrapContext bootstrapContext) {
Assert.notNull(bootstrapContext, "BootstrapContext must not be null");
this.bootstrapContext = bootstrapContext;
}
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.addBeanPostProcessor(new BootstrapContextAwareProcessor(this.bootstrapContext));
beanFactory.ignoreDependencyInterface(BootstrapContextAware.class);
beanFactory.registerResolvableDependency(BootstrapContext.class, this.bootstrapContext);
// JCA WorkManager resolved lazily - may not be available.
beanFactory.registerResolvableDependency(WorkManager.class,
(ObjectFactory<WorkManager>) this.bootstrapContext::getWorkManager);
}
}

View File

@@ -1,260 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.jca.context;
import javax.resource.NotSupportedException;
import javax.resource.ResourceException;
import javax.resource.spi.ActivationSpec;
import javax.resource.spi.BootstrapContext;
import javax.resource.spi.ResourceAdapter;
import javax.resource.spi.ResourceAdapterInternalException;
import javax.resource.spi.endpoint.MessageEndpointFactory;
import javax.transaction.xa.XAResource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* JCA 1.7 {@link javax.resource.spi.ResourceAdapter} implementation
* that loads a Spring {@link org.springframework.context.ApplicationContext},
* starting and stopping Spring-managed beans as part of the ResourceAdapter's
* lifecycle.
*
* <p>Ideal for application contexts that do not need any HTTP entry points
* but rather just consist of message endpoints and scheduled jobs etc.
* Beans in such a context may use application server resources such as the
* JTA transaction manager and JNDI-bound JDBC DataSources and JMS
* ConnectionFactory instances, and may also register with the platform's
* JMX server - all through Spring's standard transaction management and
* JNDI and JMX support facilities.
*
* <p>If the need for scheduling asynchronous work arises, consider using
* Spring's {@link org.springframework.jca.work.WorkManagerTaskExecutor}
* as a standard bean definition, to be injected into application beans
* through dependency injection. This WorkManagerTaskExecutor will automatically
* use the JCA WorkManager from the BootstrapContext that has been provided
* to this ResourceAdapter.
*
* <p>The JCA {@link javax.resource.spi.BootstrapContext} may also be
* accessed directly, through application components that implement the
* {@link BootstrapContextAware} interface. When deployed using this
* ResourceAdapter, the BootstrapContext is guaranteed to be passed on
* to such components.
*
* <p>This ResourceAdapter is to be defined in a "META-INF/ra.xml" file
* within a Java EE ".rar" deployment unit like as follows:
*
* <pre class="code">
* &lt;?xml version="1.0" encoding="UTF-8"?&gt;
* &lt;connector xmlns="http://java.sun.com/xml/ns/j2ee"
* xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
* xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee https://java.sun.com/xml/ns/j2ee/connector_1_5.xsd"
* version="1.5"&gt;
* &lt;vendor-name&gt;Spring Framework&lt;/vendor-name&gt;
* &lt;eis-type&gt;Spring Connector&lt;/eis-type&gt;
* &lt;resourceadapter-version&gt;1.0&lt;/resourceadapter-version&gt;
* &lt;resourceadapter&gt;
* &lt;resourceadapter-class&gt;org.springframework.jca.context.SpringContextResourceAdapter&lt;/resourceadapter-class&gt;
* &lt;config-property&gt;
* &lt;config-property-name&gt;ContextConfigLocation&lt;/config-property-name&gt;
* &lt;config-property-type&gt;java.lang.String&lt;/config-property-type&gt;
* &lt;config-property-value&gt;META-INF/applicationContext.xml&lt;/config-property-value&gt;
* &lt;/config-property&gt;
* &lt;/resourceadapter&gt;
* &lt;/connector&gt;</pre>
*
* Note that "META-INF/applicationContext.xml" is the default context config
* location, so it doesn't have to specified unless you intend to specify
* different/additional config files. So in the default case, you may remove
* the entire {@code config-property} section above.
*
* <p><b>For simple deployment needs, all you need to do is the following:</b>
* Package all application classes into a RAR file (which is just a standard
* JAR file with a different file extension), add all required library jars
* into the root of the RAR archive, add a "META-INF/ra.xml" deployment
* descriptor as shown above as well as the corresponding Spring XML bean
* definition file(s) (typically "META-INF/applicationContext.xml"),
* and drop the resulting RAR file into your application server's
* deployment directory!
*
* @author Juergen Hoeller
* @since 2.5
* @see #setContextConfigLocation
* @see #loadBeanDefinitions
* @see ResourceAdapterApplicationContext
*/
public class SpringContextResourceAdapter implements ResourceAdapter {
/**
* Any number of these characters are considered delimiters between
* multiple context config paths in a single String value.
* @see #setContextConfigLocation
*/
public static final String CONFIG_LOCATION_DELIMITERS = ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS;
/**
* The default {@code applicationContext.xml} location.
*/
public static final String DEFAULT_CONTEXT_CONFIG_LOCATION = "META-INF/applicationContext.xml";
protected final Log logger = LogFactory.getLog(getClass());
private String contextConfigLocation = DEFAULT_CONTEXT_CONFIG_LOCATION;
@Nullable
private ConfigurableApplicationContext applicationContext;
/**
* Set the location of the context configuration files, within the
* resource adapter's deployment unit. This can be a delimited
* String that consists of multiple resource location, separated
* by commas, semicolons, whitespace, or line breaks.
* <p>This can be specified as "ContextConfigLocation" config
* property in the {@code ra.xml} deployment descriptor.
* <p>The default is "classpath:META-INF/applicationContext.xml".
*/
public void setContextConfigLocation(String contextConfigLocation) {
this.contextConfigLocation = contextConfigLocation;
}
/**
* Return the specified context configuration files.
*/
protected String getContextConfigLocation() {
return this.contextConfigLocation;
}
/**
* Return a new {@link StandardEnvironment}.
* <p>Subclasses may override this method in order to supply
* a custom {@link ConfigurableEnvironment} implementation.
*/
protected ConfigurableEnvironment createEnvironment() {
return new StandardEnvironment();
}
/**
* This implementation loads a Spring ApplicationContext through the
* {@link #createApplicationContext} template method.
*/
@Override
public void start(BootstrapContext bootstrapContext) throws ResourceAdapterInternalException {
if (logger.isDebugEnabled()) {
logger.debug("Starting SpringContextResourceAdapter with BootstrapContext: " + bootstrapContext);
}
this.applicationContext = createApplicationContext(bootstrapContext);
}
/**
* Build a Spring ApplicationContext for the given JCA BootstrapContext.
* <p>The default implementation builds a {@link ResourceAdapterApplicationContext}
* and delegates to {@link #loadBeanDefinitions} for actually parsing the
* specified configuration files.
* @param bootstrapContext this ResourceAdapter's BootstrapContext
* @return the Spring ApplicationContext instance
*/
protected ConfigurableApplicationContext createApplicationContext(BootstrapContext bootstrapContext) {
ResourceAdapterApplicationContext applicationContext =
new ResourceAdapterApplicationContext(bootstrapContext);
// Set ResourceAdapter's ClassLoader as bean class loader.
applicationContext.setClassLoader(getClass().getClassLoader());
// Extract individual config locations.
String[] configLocations =
StringUtils.tokenizeToStringArray(getContextConfigLocation(), CONFIG_LOCATION_DELIMITERS);
loadBeanDefinitions(applicationContext, configLocations);
applicationContext.refresh();
return applicationContext;
}
/**
* Load the bean definitions into the given registry,
* based on the specified configuration files.
* @param registry the registry to load into
* @param configLocations the parsed config locations
* @see #setContextConfigLocation
*/
protected void loadBeanDefinitions(BeanDefinitionRegistry registry, String[] configLocations) {
new XmlBeanDefinitionReader(registry).loadBeanDefinitions(configLocations);
}
/**
* This implementation closes the Spring ApplicationContext.
*/
@Override
public void stop() {
logger.debug("Stopping SpringContextResourceAdapter");
if (this.applicationContext != null) {
this.applicationContext.close();
}
}
/**
* This implementation always throws a NotSupportedException.
*/
@Override
public void endpointActivation(MessageEndpointFactory messageEndpointFactory, ActivationSpec activationSpec)
throws ResourceException {
throw new NotSupportedException("SpringContextResourceAdapter does not support message endpoints");
}
/**
* This implementation does nothing.
*/
@Override
public void endpointDeactivation(MessageEndpointFactory messageEndpointFactory, ActivationSpec activationSpec) {
}
/**
* This implementation always returns {@code null}.
*/
@Override
@Nullable
public XAResource[] getXAResources(ActivationSpec[] activationSpecs) throws ResourceException {
return null;
}
@Override
public boolean equals(@Nullable Object other) {
return (this == other || (other instanceof SpringContextResourceAdapter &&
ObjectUtils.nullSafeEquals(getContextConfigLocation(),
((SpringContextResourceAdapter) other).getContextConfigLocation())));
}
@Override
public int hashCode() {
return ObjectUtils.nullSafeHashCode(getContextConfigLocation());
}
}

View File

@@ -1,10 +0,0 @@
/**
* Integration package that allows for deploying a Spring application context
* as a JCA 1.7 compliant RAR file.
*/
@NonNullApi
@NonNullFields
package org.springframework.jca.context;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -18,15 +18,15 @@ package org.springframework.jca.endpoint;
import java.lang.reflect.Method;
import javax.resource.ResourceException;
import javax.resource.spi.ApplicationServerInternalException;
import javax.resource.spi.UnavailableException;
import javax.resource.spi.endpoint.MessageEndpoint;
import javax.resource.spi.endpoint.MessageEndpointFactory;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.xa.XAResource;
import jakarta.resource.ResourceException;
import jakarta.resource.spi.ApplicationServerInternalException;
import jakarta.resource.spi.UnavailableException;
import jakarta.resource.spi.endpoint.MessageEndpoint;
import jakarta.resource.spi.endpoint.MessageEndpointFactory;
import jakarta.transaction.Transaction;
import jakarta.transaction.TransactionManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -38,7 +38,7 @@ import org.springframework.util.Assert;
/**
* Abstract base implementation of the JCA 1.7
* {@link javax.resource.spi.endpoint.MessageEndpointFactory} interface,
* {@link jakarta.resource.spi.endpoint.MessageEndpointFactory} interface,
* providing transaction management capabilities as well as ClassLoader
* exposure for endpoint invocations.
*
@@ -68,7 +68,7 @@ public abstract class AbstractMessageEndpointFactory implements MessageEndpointF
* invocations, enlisting the endpoint resource in each such transaction.
* <p>The passed-in object may be a transaction manager which implements
* Spring's {@link org.springframework.transaction.jta.TransactionFactory}
* interface, or a plain {@link javax.transaction.TransactionManager}.
* interface, or a plain {@link jakarta.transaction.TransactionManager}.
* <p>If no transaction manager is specified, the endpoint invocation
* will simply not be wrapped in an XA transaction. Check out your
* resource provider's ActivationSpec documentation for local
@@ -86,7 +86,7 @@ public abstract class AbstractMessageEndpointFactory implements MessageEndpointF
else {
throw new IllegalArgumentException("Transaction manager [" + transactionManager +
"] is neither a [org.springframework.transaction.jta.TransactionFactory} nor a " +
"[javax.transaction.TransactionManager]");
"[jakarta.transaction.TransactionManager]");
}
}

View File

@@ -16,11 +16,11 @@
package org.springframework.jca.endpoint;
import javax.resource.ResourceException;
import javax.resource.spi.UnavailableException;
import javax.resource.spi.endpoint.MessageEndpoint;
import javax.transaction.xa.XAResource;
import jakarta.resource.ResourceException;
import jakarta.resource.spi.UnavailableException;
import jakarta.resource.spi.endpoint.MessageEndpoint;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
@@ -32,10 +32,10 @@ import org.springframework.util.ReflectionUtils;
/**
* Generic implementation of the JCA 1.7
* {@link javax.resource.spi.endpoint.MessageEndpointFactory} interface,
* {@link jakarta.resource.spi.endpoint.MessageEndpointFactory} interface,
* providing transaction management capabilities for any kind of message
* listener object (e.g. {@link javax.jms.MessageListener} objects or
* {@link javax.resource.cci.MessageListener} objects.
* listener object (e.g. {@link jakarta.jms.MessageListener} objects or
* {@link jakarta.resource.cci.MessageListener} objects.
*
* <p>Uses AOP proxies for concrete endpoint instances, simply wrapping
* the specified message listener object and exposing all of its implemented
@@ -44,7 +44,7 @@ import org.springframework.util.ReflectionUtils;
* <p>Typically used with Spring's {@link GenericMessageEndpointManager},
* but not tied to it. As a consequence, this endpoint factory could
* also be used with programmatic endpoint management on a native
* {@link javax.resource.spi.ResourceAdapter} instance.
* {@link jakarta.resource.spi.ResourceAdapter} instance.
*
* @author Juergen Hoeller
* @since 2.5
@@ -60,8 +60,8 @@ public class GenericMessageEndpointFactory extends AbstractMessageEndpointFactor
/**
* Specify the message listener object that the endpoint should expose
* (e.g. a {@link javax.jms.MessageListener} objects or
* {@link javax.resource.cci.MessageListener} implementation).
* (e.g. a {@link jakarta.jms.MessageListener} objects or
* {@link jakarta.resource.cci.MessageListener} implementation).
*/
public void setMessageListener(Object messageListener) {
this.messageListener = messageListener;

View File

@@ -16,10 +16,10 @@
package org.springframework.jca.endpoint;
import javax.resource.ResourceException;
import javax.resource.spi.ActivationSpec;
import javax.resource.spi.ResourceAdapter;
import javax.resource.spi.endpoint.MessageEndpointFactory;
import jakarta.resource.ResourceException;
import jakarta.resource.spi.ActivationSpec;
import jakarta.resource.spi.ResourceAdapter;
import jakarta.resource.spi.endpoint.MessageEndpointFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
@@ -48,7 +48,7 @@ import org.springframework.util.Assert;
* &lt;property name="activationSpec"&gt;
* &lt;bean class="org.apache.activemq.ra.ActiveMQActivationSpec"&gt;
* &lt;property name="destination" value="myQueue"/&gt;
* &lt;property name="destinationType" value="javax.jms.Queue"/&gt;
* &lt;property name="destinationType" value="jakarta.jms.Queue"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;/bean&gt;</pre>
@@ -56,7 +56,7 @@ import org.springframework.util.Assert;
* In this example, Spring's own {@link GenericMessageEndpointFactory} is used
* to point to a standard message listener object that happens to be supported
* by the specified target ResourceAdapter: in this case, a JMS
* {@link javax.jms.MessageListener} object as supported by the ActiveMQ
* {@link jakarta.jms.MessageListener} object as supported by the ActiveMQ
* message broker, defined as a Spring bean:
*
* <pre class="code">
@@ -84,7 +84,7 @@ import org.springframework.util.Assert;
* For a different target resource, the configuration would simply point to a
* different ResourceAdapter and a different ActivationSpec object (which are
* both specific to the resource provider), and possibly a different message
* listener (e.g. a CCI {@link javax.resource.cci.MessageListener} for a
* listener (e.g. a CCI {@link jakarta.resource.cci.MessageListener} for a
* resource adapter which is based on the JCA Common Client Interface).
*
* <p>The asynchronous execution strategy can be customized through the
@@ -97,7 +97,7 @@ import org.springframework.util.Assert;
* as built by the specified MessageEndpointFactory. {@link GenericMessageEndpointFactory}
* supports XA transaction participation through its "transactionManager" property,
* typically with a Spring {@link org.springframework.transaction.jta.JtaTransactionManager}
* or a plain {@link javax.transaction.TransactionManager} implementation specified there.
* or a plain {@link jakarta.transaction.TransactionManager} implementation specified there.
*
* <pre class="code">
* &lt;bean class="org.springframework.jca.endpoint.GenericMessageEndpointManager"&gt;
@@ -111,7 +111,7 @@ import org.springframework.util.Assert;
* &lt;property name="activationSpec"&gt;
* &lt;bean class="org.apache.activemq.ra.ActiveMQActivationSpec"&gt;
* &lt;property name="destination" value="myQueue"/&gt;
* &lt;property name="destinationType" value="javax.jms.Queue"/&gt;
* &lt;property name="destinationType" value="jakarta.jms.Queue"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;/bean&gt;
@@ -133,7 +133,7 @@ import org.springframework.util.Assert;
* &lt;property name="activationSpec"&gt;
* &lt;bean class="org.apache.activemq.ra.ActiveMQActivationSpec"&gt;
* &lt;property name="destination" value="myQueue"/&gt;
* &lt;property name="destinationType" value="javax.jms.Queue"/&gt;
* &lt;property name="destinationType" value="jakarta.jms.Queue"/&gt;
* &lt;property name="useRAManagedTransaction" value="true"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
@@ -141,10 +141,10 @@ import org.springframework.util.Assert;
*
* @author Juergen Hoeller
* @since 2.5
* @see javax.resource.spi.ResourceAdapter#endpointActivation
* @see javax.resource.spi.ResourceAdapter#endpointDeactivation
* @see javax.resource.spi.endpoint.MessageEndpointFactory
* @see javax.resource.spi.ActivationSpec
* @see jakarta.resource.spi.ResourceAdapter#endpointActivation
* @see jakarta.resource.spi.ResourceAdapter#endpointDeactivation
* @see jakarta.resource.spi.endpoint.MessageEndpointFactory
* @see jakarta.resource.spi.ActivationSpec
*/
public class GenericMessageEndpointManager implements SmartLifecycle, InitializingBean, DisposableBean {

View File

@@ -16,9 +16,9 @@
package org.springframework.jca.support;
import javax.resource.ResourceException;
import javax.resource.spi.ConnectionManager;
import javax.resource.spi.ManagedConnectionFactory;
import jakarta.resource.ResourceException;
import jakarta.resource.spi.ConnectionManager;
import jakarta.resource.spi.ManagedConnectionFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
@@ -29,13 +29,13 @@ import org.springframework.lang.Nullable;
* a local JCA connection factory in "non-managed" mode (as defined by the
* Java Connector Architecture specification). This is a direct alternative
* to a {@link org.springframework.jndi.JndiObjectFactoryBean} definition that
* obtains a connection factory handle from a Java EE server's naming environment.
* obtains a connection factory handle from a Jakarta EE server's naming environment.
*
* <p>The type of the connection factory is dependent on the actual connector:
* the connector can either expose its native API (such as a JDBC
* {@link javax.sql.DataSource} or a JMS {@link javax.jms.ConnectionFactory})
* {@link javax.sql.DataSource} or a JMS {@link jakarta.jms.ConnectionFactory})
* or follow the standard Common Client Interface (CCI), as defined by the JCA spec.
* The exposed interface in the CCI case is {@link javax.resource.cci.ConnectionFactory}.
* The exposed interface in the CCI case is {@link jakarta.resource.cci.ConnectionFactory}.
*
* <p>In order to use this FactoryBean, you must specify the connector's
* {@link #setManagedConnectionFactory "managedConnectionFactory"} (usually
@@ -46,7 +46,7 @@ import org.springframework.lang.Nullable;
*
* <p><b>NOTE:</b> In non-managed mode, a connector is not deployed on an
* application server, or more specifically not interacting with an application
* server. Consequently, it cannot use a Java EE server's system contracts:
* server. Consequently, it cannot use a Jakarta EE server's system contracts:
* connection management, transaction management, and security management.
* A custom ConnectionManager implementation has to be used for applying those
* services in conjunction with a standalone transaction coordinator etc.
@@ -65,8 +65,8 @@ import org.springframework.lang.Nullable;
* @since 1.2
* @see #setManagedConnectionFactory
* @see #setConnectionManager
* @see javax.resource.cci.ConnectionFactory
* @see javax.resource.cci.Connection#getLocalTransaction
* @see jakarta.resource.cci.ConnectionFactory
* @see jakarta.resource.cci.Connection#getLocalTransaction
* @see org.springframework.jca.cci.connection.CciLocalTransactionManager
*/
public class LocalConnectionFactoryBean implements FactoryBean<Object>, InitializingBean {
@@ -91,11 +91,11 @@ public class LocalConnectionFactoryBean implements FactoryBean<Object>, Initiali
* EntityManagerFactory.
* <p>Note that the ManagerConnectionFactory implementation might expect
* a reference to its JCA 1.7 ResourceAdapter, expressed through the
* {@link javax.resource.spi.ResourceAdapterAssociation} interface.
* {@link jakarta.resource.spi.ResourceAdapterAssociation} interface.
* Simply inject the corresponding ResourceAdapter instance into its
* "resourceAdapter" bean property in this case, before passing the
* ManagerConnectionFactory into this LocalConnectionFactoryBean.
* @see javax.resource.spi.ManagedConnectionFactory#createConnectionFactory()
* @see jakarta.resource.spi.ManagedConnectionFactory#createConnectionFactory()
*/
public void setManagedConnectionFactory(ManagedConnectionFactory managedConnectionFactory) {
this.managedConnectionFactory = managedConnectionFactory;
@@ -107,7 +107,7 @@ public class LocalConnectionFactoryBean implements FactoryBean<Object>, Initiali
* <p>A ConnectionManager implementation for local usage is often
* included with a JCA connector. Such an included ConnectionManager
* might be set as default, with no need to explicitly specify one.
* @see javax.resource.spi.ManagedConnectionFactory#createConnectionFactory(javax.resource.spi.ConnectionManager)
* @see jakarta.resource.spi.ManagedConnectionFactory#createConnectionFactory(jakarta.resource.spi.ConnectionManager)
*/
public void setConnectionManager(ConnectionManager connectionManager) {
this.connectionManager = connectionManager;

View File

@@ -16,11 +16,11 @@
package org.springframework.jca.support;
import javax.resource.ResourceException;
import javax.resource.spi.BootstrapContext;
import javax.resource.spi.ResourceAdapter;
import javax.resource.spi.XATerminator;
import javax.resource.spi.work.WorkManager;
import jakarta.resource.ResourceException;
import jakarta.resource.spi.BootstrapContext;
import jakarta.resource.spi.ResourceAdapter;
import jakarta.resource.spi.XATerminator;
import jakarta.resource.spi.work.WorkManager;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.DisposableBean;
@@ -30,8 +30,8 @@ import org.springframework.lang.Nullable;
/**
* {@link org.springframework.beans.factory.FactoryBean} that bootstraps
* the specified JCA 1.7 {@link javax.resource.spi.ResourceAdapter},
* starting it with a local {@link javax.resource.spi.BootstrapContext}
* the specified JCA 1.7 {@link jakarta.resource.spi.ResourceAdapter},
* starting it with a local {@link jakarta.resource.spi.BootstrapContext}
* and exposing it for bean references. It will also stop the ResourceAdapter
* on context shutdown. This corresponds to 'non-managed' bootstrap in a
* local environment, according to the JCA 1.7 specification.
@@ -45,8 +45,8 @@ import org.springframework.lang.Nullable;
* @see #setResourceAdapter
* @see #setBootstrapContext
* @see #setWorkManager
* @see javax.resource.spi.ResourceAdapter#start(javax.resource.spi.BootstrapContext)
* @see javax.resource.spi.ResourceAdapter#stop()
* @see jakarta.resource.spi.ResourceAdapter#start(jakarta.resource.spi.BootstrapContext)
* @see jakarta.resource.spi.ResourceAdapter#stop()
*/
public class ResourceAdapterFactoryBean implements FactoryBean<ResourceAdapter>, InitializingBean, DisposableBean {
@@ -114,7 +114,7 @@ public class ResourceAdapterFactoryBean implements FactoryBean<ResourceAdapter>,
/**
* Builds the BootstrapContext and starts the ResourceAdapter with it.
* @see javax.resource.spi.ResourceAdapter#start(javax.resource.spi.BootstrapContext)
* @see jakarta.resource.spi.ResourceAdapter#start(jakarta.resource.spi.BootstrapContext)
*/
@Override
public void afterPropertiesSet() throws ResourceException {
@@ -147,7 +147,7 @@ public class ResourceAdapterFactoryBean implements FactoryBean<ResourceAdapter>,
/**
* Stops the ResourceAdapter.
* @see javax.resource.spi.ResourceAdapter#stop()
* @see jakarta.resource.spi.ResourceAdapter#stop()
*/
@Override
public void destroy() {

View File

@@ -18,18 +18,18 @@ package org.springframework.jca.support;
import java.util.Timer;
import javax.resource.spi.BootstrapContext;
import javax.resource.spi.UnavailableException;
import javax.resource.spi.XATerminator;
import javax.resource.spi.work.WorkContext;
import javax.resource.spi.work.WorkManager;
import javax.transaction.TransactionSynchronizationRegistry;
import jakarta.resource.spi.BootstrapContext;
import jakarta.resource.spi.UnavailableException;
import jakarta.resource.spi.XATerminator;
import jakarta.resource.spi.work.WorkContext;
import jakarta.resource.spi.work.WorkManager;
import jakarta.transaction.TransactionSynchronizationRegistry;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Simple implementation of the JCA 1.7 {@link javax.resource.spi.BootstrapContext}
* Simple implementation of the JCA 1.7 {@link jakarta.resource.spi.BootstrapContext}
* interface, used for bootstrapping a JCA ResourceAdapter in a local environment.
*
* <p>Delegates to the given WorkManager and XATerminator, if any. Creates simple
@@ -37,7 +37,7 @@ import org.springframework.util.Assert;
*
* @author Juergen Hoeller
* @since 2.0.3
* @see javax.resource.spi.ResourceAdapter#start(javax.resource.spi.BootstrapContext)
* @see jakarta.resource.spi.ResourceAdapter#start(jakarta.resource.spi.BootstrapContext)
* @see ResourceAdapterFactoryBean
*/
public class SimpleBootstrapContext implements BootstrapContext {

View File

@@ -1,69 +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
*
* https://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.jca.work;
import javax.resource.spi.work.Work;
import org.springframework.util.Assert;
/**
* Simple Work adapter that delegates to a given Runnable.
*
* @author Juergen Hoeller
* @since 2.0.3
* @see javax.resource.spi.work.Work
* @see Runnable
*/
public class DelegatingWork implements Work {
private final Runnable delegate;
/**
* Create a new DelegatingWork.
* @param delegate the Runnable implementation to delegate to
*/
public DelegatingWork(Runnable delegate) {
Assert.notNull(delegate, "Delegate must not be null");
this.delegate = delegate;
}
/**
* Return the wrapped Runnable implementation.
*/
public final Runnable getDelegate() {
return this.delegate;
}
/**
* Delegates execution to the underlying Runnable.
*/
@Override
public void run() {
this.delegate.run();
}
/**
* This implementation is empty, since we expect the Runnable
* to terminate based on some specific shutdown signal.
*/
@Override
public void release() {
}
}

View File

@@ -1,257 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.jca.work;
import javax.resource.spi.work.ExecutionContext;
import javax.resource.spi.work.Work;
import javax.resource.spi.work.WorkAdapter;
import javax.resource.spi.work.WorkCompletedException;
import javax.resource.spi.work.WorkEvent;
import javax.resource.spi.work.WorkException;
import javax.resource.spi.work.WorkListener;
import javax.resource.spi.work.WorkManager;
import javax.resource.spi.work.WorkRejectedException;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.core.task.TaskRejectedException;
import org.springframework.core.task.TaskTimeoutException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Simple JCA 1.7 {@link javax.resource.spi.work.WorkManager} implementation that
* delegates to a Spring {@link org.springframework.core.task.TaskExecutor}.
* Provides simple task execution including start timeouts, but without support
* for a JCA ExecutionContext (i.e. without support for imported transactions).
*
* <p>Uses a {@link org.springframework.core.task.SyncTaskExecutor} for {@link #doWork}
* calls and a {@link org.springframework.core.task.SimpleAsyncTaskExecutor}
* for {@link #startWork} and {@link #scheduleWork} calls, by default.
* These default task executors can be overridden through configuration.
*
* <p><b>NOTE: This WorkManager does not provide thread pooling by default!</b>
* Specify a {@link org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor}
* (or any other thread-pooling TaskExecutor) as "asyncTaskExecutor" in order to
* achieve actual thread pooling.
*
* <p>This WorkManager automatically detects a specified
* {@link org.springframework.core.task.AsyncTaskExecutor} implementation
* and uses its extended timeout functionality where appropriate.
* JCA WorkListeners are fully supported in any case.
*
* @author Juergen Hoeller
* @since 2.0.3
* @see #setSyncTaskExecutor
* @see #setAsyncTaskExecutor
*/
public class SimpleTaskWorkManager implements WorkManager {
@Nullable
private TaskExecutor syncTaskExecutor = new SyncTaskExecutor();
@Nullable
private AsyncTaskExecutor asyncTaskExecutor = new SimpleAsyncTaskExecutor();
/**
* Specify the TaskExecutor to use for <i>synchronous</i> work execution
* (i.e. {@link #doWork} calls).
* <p>Default is a {@link org.springframework.core.task.SyncTaskExecutor}.
*/
public void setSyncTaskExecutor(TaskExecutor syncTaskExecutor) {
this.syncTaskExecutor = syncTaskExecutor;
}
/**
* Specify the TaskExecutor to use for <i>asynchronous</i> work execution
* (i.e. {@link #startWork} and {@link #scheduleWork} calls).
* <p>This will typically (but not necessarily) be an
* {@link org.springframework.core.task.AsyncTaskExecutor} implementation.
* Default is a {@link org.springframework.core.task.SimpleAsyncTaskExecutor}.
*/
public void setAsyncTaskExecutor(AsyncTaskExecutor asyncTaskExecutor) {
this.asyncTaskExecutor = asyncTaskExecutor;
}
@Override
public void doWork(Work work) throws WorkException {
doWork(work, WorkManager.INDEFINITE, null, null);
}
@Override
public void doWork(Work work, long startTimeout, @Nullable ExecutionContext executionContext, @Nullable WorkListener workListener)
throws WorkException {
Assert.state(this.syncTaskExecutor != null, "No 'syncTaskExecutor' set");
executeWork(this.syncTaskExecutor, work, startTimeout, false, executionContext, workListener);
}
@Override
public long startWork(Work work) throws WorkException {
return startWork(work, WorkManager.INDEFINITE, null, null);
}
@Override
public long startWork(Work work, long startTimeout, @Nullable ExecutionContext executionContext, @Nullable WorkListener workListener)
throws WorkException {
Assert.state(this.asyncTaskExecutor != null, "No 'asyncTaskExecutor' set");
return executeWork(this.asyncTaskExecutor, work, startTimeout, true, executionContext, workListener);
}
@Override
public void scheduleWork(Work work) throws WorkException {
scheduleWork(work, WorkManager.INDEFINITE, null, null);
}
@Override
public void scheduleWork(Work work, long startTimeout, @Nullable ExecutionContext executionContext, @Nullable WorkListener workListener)
throws WorkException {
Assert.state(this.asyncTaskExecutor != null, "No 'asyncTaskExecutor' set");
executeWork(this.asyncTaskExecutor, work, startTimeout, false, executionContext, workListener);
}
/**
* Execute the given Work on the specified TaskExecutor.
* @param taskExecutor the TaskExecutor to use
* @param work the Work to execute
* @param startTimeout the time duration within which the Work is supposed to start
* @param blockUntilStarted whether to block until the Work has started
* @param executionContext the JCA ExecutionContext for the given Work
* @param workListener the WorkListener to clal for the given Work
* @return the time elapsed from Work acceptance until start of execution
* (or -1 if not applicable or not known)
* @throws WorkException if the TaskExecutor did not accept the Work
*/
protected long executeWork(TaskExecutor taskExecutor, Work work, long startTimeout, boolean blockUntilStarted,
@Nullable ExecutionContext executionContext, @Nullable WorkListener workListener) throws WorkException {
if (executionContext != null && executionContext.getXid() != null) {
throw new WorkException("SimpleTaskWorkManager does not supported imported XIDs: " + executionContext.getXid());
}
WorkListener workListenerToUse = workListener;
if (workListenerToUse == null) {
workListenerToUse = new WorkAdapter();
}
boolean isAsync = (taskExecutor instanceof AsyncTaskExecutor);
DelegatingWorkAdapter workHandle = new DelegatingWorkAdapter(work, workListenerToUse, !isAsync);
try {
if (isAsync) {
((AsyncTaskExecutor) taskExecutor).execute(workHandle, startTimeout);
}
else {
taskExecutor.execute(workHandle);
}
}
catch (TaskTimeoutException ex) {
WorkException wex = new WorkRejectedException("TaskExecutor rejected Work because of timeout: " + work, ex);
wex.setErrorCode(WorkException.START_TIMED_OUT);
workListenerToUse.workRejected(new WorkEvent(this, WorkEvent.WORK_REJECTED, work, wex));
throw wex;
}
catch (TaskRejectedException ex) {
WorkException wex = new WorkRejectedException("TaskExecutor rejected Work: " + work, ex);
wex.setErrorCode(WorkException.INTERNAL);
workListenerToUse.workRejected(new WorkEvent(this, WorkEvent.WORK_REJECTED, work, wex));
throw wex;
}
catch (Throwable ex) {
WorkException wex = new WorkException("TaskExecutor failed to execute Work: " + work, ex);
wex.setErrorCode(WorkException.INTERNAL);
throw wex;
}
if (isAsync) {
workListenerToUse.workAccepted(new WorkEvent(this, WorkEvent.WORK_ACCEPTED, work, null));
}
if (blockUntilStarted) {
long acceptanceTime = System.currentTimeMillis();
synchronized (workHandle.monitor) {
try {
while (!workHandle.started) {
workHandle.monitor.wait();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
return (System.currentTimeMillis() - acceptanceTime);
}
else {
return WorkManager.UNKNOWN;
}
}
/**
* Work adapter that supports start timeouts and WorkListener callbacks
* for a given Work that it delegates to.
*/
private static class DelegatingWorkAdapter implements Work {
private final Work work;
private final WorkListener workListener;
private final boolean acceptOnExecution;
public final Object monitor = new Object();
public boolean started = false;
public DelegatingWorkAdapter(Work work, WorkListener workListener, boolean acceptOnExecution) {
this.work = work;
this.workListener = workListener;
this.acceptOnExecution = acceptOnExecution;
}
@Override
public void run() {
if (this.acceptOnExecution) {
this.workListener.workAccepted(new WorkEvent(this, WorkEvent.WORK_ACCEPTED, this.work, null));
}
synchronized (this.monitor) {
this.started = true;
this.monitor.notify();
}
this.workListener.workStarted(new WorkEvent(this, WorkEvent.WORK_STARTED, this.work, null));
try {
this.work.run();
}
catch (RuntimeException | Error ex) {
this.workListener.workCompleted(
new WorkEvent(this, WorkEvent.WORK_COMPLETED, this.work, new WorkCompletedException(ex)));
throw ex;
}
this.workListener.workCompleted(new WorkEvent(this, WorkEvent.WORK_COMPLETED, this.work, null));
}
@Override
public void release() {
this.work.release();
}
}
}

View File

@@ -1,337 +0,0 @@
/*
* Copyright 2002-2020 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
*
* https://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.jca.work;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import javax.naming.NamingException;
import javax.resource.spi.BootstrapContext;
import javax.resource.spi.work.ExecutionContext;
import javax.resource.spi.work.Work;
import javax.resource.spi.work.WorkException;
import javax.resource.spi.work.WorkListener;
import javax.resource.spi.work.WorkManager;
import javax.resource.spi.work.WorkRejectedException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.task.AsyncListenableTaskExecutor;
import org.springframework.core.task.TaskDecorator;
import org.springframework.core.task.TaskRejectedException;
import org.springframework.core.task.TaskTimeoutException;
import org.springframework.jca.context.BootstrapContextAware;
import org.springframework.jndi.JndiLocatorSupport;
import org.springframework.lang.Nullable;
import org.springframework.scheduling.SchedulingException;
import org.springframework.scheduling.SchedulingTaskExecutor;
import org.springframework.util.Assert;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureTask;
/**
* {@link org.springframework.core.task.TaskExecutor} implementation
* that delegates to a JCA 1.7 WorkManager, implementing the
* {@link javax.resource.spi.work.WorkManager} interface.
*
* <p>This is mainly intended for use within a JCA ResourceAdapter implementation,
* but may also be used in a standalone environment, delegating to a locally
* embedded WorkManager implementation (such as Geronimo's).
*
* <p>Also implements the JCA 1.7 WorkManager interface itself, delegating all
* calls to the target WorkManager. Hence, a caller can choose whether it wants
* to talk to this executor through the Spring TaskExecutor interface or the
* WorkManager interface.
*
* <p>This adapter is also capable of obtaining a JCA WorkManager from JNDI.
* This is for example appropriate on the Geronimo application server, where
* WorkManager GBeans (e.g. Geronimo's default "DefaultWorkManager" GBean)
* can be linked into the Java EE environment through "gbean-ref" entries
* in the {@code geronimo-web.xml} deployment descriptor.
*
* @author Juergen Hoeller
* @since 2.0.3
* @see #setWorkManager
* @see javax.resource.spi.work.WorkManager#scheduleWork
*/
public class WorkManagerTaskExecutor extends JndiLocatorSupport
implements AsyncListenableTaskExecutor, SchedulingTaskExecutor, WorkManager, BootstrapContextAware, InitializingBean {
@Nullable
private WorkManager workManager;
@Nullable
private String workManagerName;
private boolean blockUntilStarted = false;
private boolean blockUntilCompleted = false;
@Nullable
private WorkListener workListener;
@Nullable
private TaskDecorator taskDecorator;
/**
* Create a new WorkManagerTaskExecutor, expecting bean-style configuration.
* @see #setWorkManager
*/
public WorkManagerTaskExecutor() {
}
/**
* Create a new WorkManagerTaskExecutor for the given WorkManager.
* @param workManager the JCA WorkManager to delegate to
*/
public WorkManagerTaskExecutor(WorkManager workManager) {
setWorkManager(workManager);
}
/**
* Specify the JCA WorkManager instance to delegate to.
*/
public void setWorkManager(WorkManager workManager) {
Assert.notNull(workManager, "WorkManager must not be null");
this.workManager = workManager;
}
/**
* Set the JNDI name of the JCA WorkManager.
* <p>This can either be a fully qualified JNDI name,
* or the JNDI name relative to the current environment
* naming context if "resourceRef" is set to "true".
* @see #setWorkManager
* @see #setResourceRef
*/
public void setWorkManagerName(String workManagerName) {
this.workManagerName = workManagerName;
}
/**
* Specify the JCA BootstrapContext that contains the
* WorkManager to delegate to.
*/
@Override
public void setBootstrapContext(BootstrapContext bootstrapContext) {
Assert.notNull(bootstrapContext, "BootstrapContext must not be null");
this.workManager = bootstrapContext.getWorkManager();
}
/**
* Set whether to let {@link #execute} block until the work
* has been actually started.
* <p>Uses the JCA {@code startWork} operation underneath,
* instead of the default {@code scheduleWork}.
* @see javax.resource.spi.work.WorkManager#startWork
* @see javax.resource.spi.work.WorkManager#scheduleWork
*/
public void setBlockUntilStarted(boolean blockUntilStarted) {
this.blockUntilStarted = blockUntilStarted;
}
/**
* Set whether to let {@link #execute} block until the work
* has been completed.
* <p>Uses the JCA {@code doWork} operation underneath,
* instead of the default {@code scheduleWork}.
* @see javax.resource.spi.work.WorkManager#doWork
* @see javax.resource.spi.work.WorkManager#scheduleWork
*/
public void setBlockUntilCompleted(boolean blockUntilCompleted) {
this.blockUntilCompleted = blockUntilCompleted;
}
/**
* Specify a JCA WorkListener to apply, if any.
* <p>This shared WorkListener instance will be passed on to the
* WorkManager by all {@link #execute} calls on this TaskExecutor.
*/
public void setWorkListener(@Nullable WorkListener workListener) {
this.workListener = workListener;
}
/**
* Specify a custom {@link TaskDecorator} to be applied to any {@link Runnable}
* about to be executed.
* <p>Note that such a decorator is not necessarily being applied to the
* user-supplied {@code Runnable}/{@code Callable} but rather to the actual
* execution callback (which may be a wrapper around the user-supplied task).
* <p>The primary use case is to set some execution context around the task's
* invocation, or to provide some monitoring/statistics for task execution.
* <p><b>NOTE:</b> Exception handling in {@code TaskDecorator} implementations
* is limited to plain {@code Runnable} execution via {@code execute} calls.
* In case of {@code #submit} calls, the exposed {@code Runnable} will be a
* {@code FutureTask} which does not propagate any exceptions; you might
* have to cast it and call {@code Future#get} to evaluate exceptions.
* @since 4.3
*/
public void setTaskDecorator(TaskDecorator taskDecorator) {
this.taskDecorator = taskDecorator;
}
@Override
public void afterPropertiesSet() throws NamingException {
if (this.workManager == null) {
if (this.workManagerName != null) {
this.workManager = lookup(this.workManagerName, WorkManager.class);
}
else {
this.workManager = getDefaultWorkManager();
}
}
}
/**
* Obtain a default WorkManager to delegate to.
* Called if no explicit WorkManager or WorkManager JNDI name has been specified.
* <p>The default implementation returns a {@link SimpleTaskWorkManager}.
* Can be overridden in subclasses.
*/
protected WorkManager getDefaultWorkManager() {
return new SimpleTaskWorkManager();
}
private WorkManager obtainWorkManager() {
Assert.state(this.workManager != null, "No WorkManager specified");
return this.workManager;
}
//-------------------------------------------------------------------------
// Implementation of the Spring SchedulingTaskExecutor interface
//-------------------------------------------------------------------------
@Override
public void execute(Runnable task) {
execute(task, TIMEOUT_INDEFINITE);
}
@Override
public void execute(Runnable task, long startTimeout) {
Work work = new DelegatingWork(this.taskDecorator != null ? this.taskDecorator.decorate(task) : task);
try {
if (this.blockUntilCompleted) {
if (startTimeout != TIMEOUT_INDEFINITE || this.workListener != null) {
obtainWorkManager().doWork(work, startTimeout, null, this.workListener);
}
else {
obtainWorkManager().doWork(work);
}
}
else if (this.blockUntilStarted) {
if (startTimeout != TIMEOUT_INDEFINITE || this.workListener != null) {
obtainWorkManager().startWork(work, startTimeout, null, this.workListener);
}
else {
obtainWorkManager().startWork(work);
}
}
else {
if (startTimeout != TIMEOUT_INDEFINITE || this.workListener != null) {
obtainWorkManager().scheduleWork(work, startTimeout, null, this.workListener);
}
else {
obtainWorkManager().scheduleWork(work);
}
}
}
catch (WorkRejectedException ex) {
if (WorkException.START_TIMED_OUT.equals(ex.getErrorCode())) {
throw new TaskTimeoutException("JCA WorkManager rejected task because of timeout: " + task, ex);
}
else {
throw new TaskRejectedException("JCA WorkManager rejected task: " + task, ex);
}
}
catch (WorkException ex) {
throw new SchedulingException("Could not schedule task on JCA WorkManager", ex);
}
}
@Override
public Future<?> submit(Runnable task) {
FutureTask<Object> future = new FutureTask<>(task, null);
execute(future, TIMEOUT_INDEFINITE);
return future;
}
@Override
public <T> Future<T> submit(Callable<T> task) {
FutureTask<T> future = new FutureTask<>(task);
execute(future, TIMEOUT_INDEFINITE);
return future;
}
@Override
public ListenableFuture<?> submitListenable(Runnable task) {
ListenableFutureTask<Object> future = new ListenableFutureTask<>(task, null);
execute(future, TIMEOUT_INDEFINITE);
return future;
}
@Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
ListenableFutureTask<T> future = new ListenableFutureTask<>(task);
execute(future, TIMEOUT_INDEFINITE);
return future;
}
//-------------------------------------------------------------------------
// Implementation of the JCA WorkManager interface
//-------------------------------------------------------------------------
@Override
public void doWork(Work work) throws WorkException {
obtainWorkManager().doWork(work);
}
@Override
public void doWork(Work work, long delay, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
obtainWorkManager().doWork(work, delay, executionContext, workListener);
}
@Override
public long startWork(Work work) throws WorkException {
return obtainWorkManager().startWork(work);
}
@Override
public long startWork(Work work, long delay, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
return obtainWorkManager().startWork(work, delay, executionContext, workListener);
}
@Override
public void scheduleWork(Work work) throws WorkException {
obtainWorkManager().scheduleWork(work);
}
@Override
public void scheduleWork(Work work, long delay, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
obtainWorkManager().scheduleWork(work, delay, executionContext, workListener);
}
}

View File

@@ -1,10 +0,0 @@
/**
* Convenience classes for scheduling based on the JCA WorkManager facility,
* as supported within ResourceAdapters.
*/
@NonNullApi
@NonNullFields
package org.springframework.jca.work;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -86,8 +86,8 @@ public interface TransactionDefinition {
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code javax.transaction.TransactionManager} to be
* made available it to it (which is server-specific in standard Java EE).
* which requires the {@code jakarta.transaction.TransactionManager} to be
* made available it to it (which is server-specific in standard Jakarta EE).
* <p>A {@code PROPAGATION_REQUIRES_NEW} scope always defines its own
* transaction synchronizations. Existing synchronizations will be suspended
* and resumed appropriately.
@@ -101,8 +101,8 @@ public interface TransactionDefinition {
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code javax.transaction.TransactionManager} to be
* made available it to it (which is server-specific in standard Java EE).
* which requires the {@code jakarta.transaction.TransactionManager} to be
* made available it to it (which is server-specific in standard Jakarta EE).
* <p>Note that transaction synchronization is <i>not</i> available within a
* {@code PROPAGATION_NOT_SUPPORTED} scope. Existing synchronizations
* will be suspended and resumed appropriately.

View File

@@ -37,8 +37,8 @@ import org.springframework.util.ClassUtils;
*
* <p>This class reads Spring's JDK 1.5+ {@link Transactional} annotation and
* exposes corresponding transaction attributes to Spring's transaction infrastructure.
* Also supports JTA 1.2's {@link javax.transaction.Transactional} and EJB3's
* {@link javax.ejb.TransactionAttribute} annotation (if present).
* Also supports JTA 1.2's {@link jakarta.transaction.Transactional} and EJB3's
* {@link jakarta.ejb.TransactionAttribute} annotation (if present).
* This class may also serve as base class for a custom TransactionAttributeSource,
* or get customized through {@link TransactionAnnotationParser} strategies.
*
@@ -62,8 +62,8 @@ public class AnnotationTransactionAttributeSource extends AbstractFallbackTransa
static {
ClassLoader classLoader = AnnotationTransactionAttributeSource.class.getClassLoader();
jta12Present = ClassUtils.isPresent("javax.transaction.Transactional", classLoader);
ejb3Present = ClassUtils.isPresent("javax.ejb.TransactionAttribute", classLoader);
jta12Present = ClassUtils.isPresent("jakarta.transaction.Transactional", classLoader);
ejb3Present = ClassUtils.isPresent("jakarta.ejb.TransactionAttribute", classLoader);
}
private final boolean publicMethodsOnly;
@@ -74,7 +74,7 @@ public class AnnotationTransactionAttributeSource extends AbstractFallbackTransa
/**
* Create a default AnnotationTransactionAttributeSource, supporting
* public methods that carry the {@code Transactional} annotation
* or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
* or the EJB3 {@link jakarta.ejb.TransactionAttribute} annotation.
*/
public AnnotationTransactionAttributeSource() {
this(true);
@@ -83,7 +83,7 @@ public class AnnotationTransactionAttributeSource extends AbstractFallbackTransa
/**
* Create a custom AnnotationTransactionAttributeSource, supporting
* public methods that carry the {@code Transactional} annotation
* or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
* or the EJB3 {@link jakarta.ejb.TransactionAttribute} annotation.
* @param publicMethodsOnly whether to support public methods that carry
* the {@code Transactional} annotation only (typically for use
* with proxy-based AOP), or protected/private methods as well

View File

@@ -19,8 +19,8 @@ package org.springframework.transaction.annotation;
import java.io.Serializable;
import java.lang.reflect.AnnotatedElement;
import javax.ejb.ApplicationException;
import javax.ejb.TransactionAttributeType;
import jakarta.ejb.ApplicationException;
import jakarta.ejb.TransactionAttributeType;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.Nullable;
@@ -28,7 +28,7 @@ import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttribute;
/**
* Strategy implementation for parsing EJB3's {@link javax.ejb.TransactionAttribute}
* Strategy implementation for parsing EJB3's {@link jakarta.ejb.TransactionAttribute}
* annotation.
*
* @author Juergen Hoeller
@@ -39,13 +39,13 @@ public class Ejb3TransactionAnnotationParser implements TransactionAnnotationPar
@Override
public boolean isCandidateClass(Class<?> targetClass) {
return AnnotationUtils.isCandidateClass(targetClass, javax.ejb.TransactionAttribute.class);
return AnnotationUtils.isCandidateClass(targetClass, jakarta.ejb.TransactionAttribute.class);
}
@Override
@Nullable
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
javax.ejb.TransactionAttribute ann = element.getAnnotation(javax.ejb.TransactionAttribute.class);
jakarta.ejb.TransactionAttribute ann = element.getAnnotation(jakarta.ejb.TransactionAttribute.class);
if (ann != null) {
return parseTransactionAnnotation(ann);
}
@@ -54,7 +54,7 @@ public class Ejb3TransactionAnnotationParser implements TransactionAnnotationPar
}
}
public TransactionAttribute parseTransactionAnnotation(javax.ejb.TransactionAttribute ann) {
public TransactionAttribute parseTransactionAnnotation(jakarta.ejb.TransactionAttribute ann) {
return new Ejb3TransactionAttribute(ann.value());
}

View File

@@ -31,7 +31,7 @@ import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute
import org.springframework.transaction.interceptor.TransactionAttribute;
/**
* Strategy implementation for parsing JTA 1.2's {@link javax.transaction.Transactional} annotation.
* Strategy implementation for parsing JTA 1.2's {@link jakarta.transaction.Transactional} annotation.
*
* @author Juergen Hoeller
* @since 4.0
@@ -41,14 +41,14 @@ public class JtaTransactionAnnotationParser implements TransactionAnnotationPars
@Override
public boolean isCandidateClass(Class<?> targetClass) {
return AnnotationUtils.isCandidateClass(targetClass, javax.transaction.Transactional.class);
return AnnotationUtils.isCandidateClass(targetClass, jakarta.transaction.Transactional.class);
}
@Override
@Nullable
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(
element, javax.transaction.Transactional.class);
element, jakarta.transaction.Transactional.class);
if (attributes != null) {
return parseTransactionAnnotation(attributes);
}
@@ -57,7 +57,7 @@ public class JtaTransactionAnnotationParser implements TransactionAnnotationPars
}
}
public TransactionAttribute parseTransactionAnnotation(javax.transaction.Transactional ann) {
public TransactionAttribute parseTransactionAnnotation(jakarta.transaction.Transactional ann) {
return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));
}

View File

@@ -61,8 +61,8 @@ public enum Propagation {
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code javax.transaction.TransactionManager} to be
* made available to it (which is server-specific in standard Java EE).
* which requires the {@code jakarta.transaction.TransactionManager} to be
* made available to it (which is server-specific in standard Jakarta EE).
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
@@ -73,8 +73,8 @@ public enum Propagation {
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code javax.transaction.TransactionManager} to be
* made available to it (which is server-specific in standard Java EE).
* which requires the {@code jakarta.transaction.TransactionManager} to be
* made available to it (which is server-specific in standard Jakarta EE).
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),

View File

@@ -25,8 +25,8 @@ import org.springframework.transaction.interceptor.TransactionAttribute;
* Strategy interface for parsing known transaction annotation types.
* {@link AnnotationTransactionAttributeSource} delegates to such
* parsers for supporting specific annotation types such as Spring's own
* {@link Transactional}, JTA 1.2's {@link javax.transaction.Transactional}
* or EJB3's {@link javax.ejb.TransactionAttribute}.
* {@link Transactional}, JTA 1.2's {@link jakarta.transaction.Transactional}
* or EJB3's {@link jakarta.ejb.TransactionAttribute}.
*
* @author Juergen Hoeller
* @since 2.5

View File

@@ -57,7 +57,7 @@ public class TransactionManagementConfigurationSelector extends AdviceModeImport
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
return (ClassUtils.isPresent("jakarta.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}

View File

@@ -188,7 +188,7 @@ public @interface Transactional {
* a transaction rollback.
* <p>This can be a substring of a fully qualified class name, with no wildcard
* support at present. For example, a value of {@code "ServletException"} would
* match {@code javax.servlet.ServletException} and its subclasses.
* match {@code jakarta.servlet.ServletException} and its subclasses.
* <p><b>NB:</b> Consider carefully how specific the pattern is and whether
* to include package information (which isn't mandatory). For example,
* {@code "Exception"} will match nearly anything and will probably hide other

View File

@@ -65,7 +65,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
if ("aspectj".equals(mode)) {
// mode="aspectj"
registerTransactionAspect(element, parserContext);
if (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader())) {
if (ClassUtils.isPresent("jakarta.transaction.Transactional", getClass().getClassLoader())) {
registerJtaTransactionAspect(element, parserContext);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2021 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.
@@ -21,23 +21,20 @@ import org.w3c.dom.Element;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.transaction.jta.JtaTransactionManager;
/**
* Parser for the &lt;tx:jta-transaction-manager/&gt; XML configuration element,
* autodetecting WebLogic and WebSphere servers and exposing the corresponding
* {@link org.springframework.transaction.jta.JtaTransactionManager} subclass.
* Parser for the &lt;tx:jta-transaction-manager/&gt; XML configuration element.
*
* @author Juergen Hoeller
* @author Christian Dupuis
* @since 2.5
* @see org.springframework.transaction.jta.WebLogicJtaTransactionManager
* @see org.springframework.transaction.jta.WebSphereUowTransactionManager
*/
public class JtaTransactionManagerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected String getBeanClassName(Element element) {
return JtaTransactionManagerFactoryBean.resolveJtaTransactionManagerClassName();
protected Class<?> getBeanClass(Element element) {
return JtaTransactionManager.class;
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 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.
@@ -16,62 +16,23 @@
package org.springframework.transaction.config;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.util.ClassUtils;
/**
* A {@link FactoryBean} equivalent to the &lt;tx:jta-transaction-manager/&gt; XML element,
* autodetecting WebLogic and WebSphere servers and exposing the corresponding
* {@link org.springframework.transaction.jta.JtaTransactionManager} subclass.
* A {@link FactoryBean} equivalent to the &lt;tx:jta-transaction-manager/&gt; XML element.
*
* @author Juergen Hoeller
* @since 4.1.1
* @see org.springframework.transaction.jta.WebLogicJtaTransactionManager
* @see org.springframework.transaction.jta.WebSphereUowTransactionManager
* @deprecated as of 6.0, in favor of a straight {@link JtaTransactionManager} definition
*/
@Deprecated
public class JtaTransactionManagerFactoryBean implements FactoryBean<JtaTransactionManager>, InitializingBean {
private static final String WEBLOGIC_JTA_TRANSACTION_MANAGER_CLASS_NAME =
"org.springframework.transaction.jta.WebLogicJtaTransactionManager";
private static final String WEBSPHERE_TRANSACTION_MANAGER_CLASS_NAME =
"org.springframework.transaction.jta.WebSphereUowTransactionManager";
private static final String JTA_TRANSACTION_MANAGER_CLASS_NAME =
"org.springframework.transaction.jta.JtaTransactionManager";
private static final boolean weblogicPresent;
private static final boolean webspherePresent;
static {
ClassLoader classLoader = JtaTransactionManagerFactoryBean.class.getClassLoader();
weblogicPresent = ClassUtils.isPresent("weblogic.transaction.UserTransaction", classLoader);
webspherePresent = ClassUtils.isPresent("com.ibm.wsspi.uow.UOWManager", classLoader);
}
private final JtaTransactionManager transactionManager;
@SuppressWarnings("unchecked")
public JtaTransactionManagerFactoryBean() {
String className = resolveJtaTransactionManagerClassName();
try {
Class<? extends JtaTransactionManager> clazz = (Class<? extends JtaTransactionManager>)
ClassUtils.forName(className, JtaTransactionManagerFactoryBean.class.getClassLoader());
this.transactionManager = BeanUtils.instantiateClass(clazz);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException("Failed to load JtaTransactionManager class: " + className, ex);
}
}
private final JtaTransactionManager transactionManager = new JtaTransactionManager();
@Override
@@ -95,17 +56,4 @@ public class JtaTransactionManagerFactoryBean implements FactoryBean<JtaTransact
return true;
}
static String resolveJtaTransactionManagerClassName() {
if (weblogicPresent) {
return WEBLOGIC_JTA_TRANSACTION_MANAGER_CLASS_NAME;
}
else if (webspherePresent) {
return WEBSPHERE_TRANSACTION_MANAGER_CLASS_NAME;
}
else {
return JTA_TRANSACTION_MANAGER_CLASS_NAME;
}
}
}

View File

@@ -74,7 +74,7 @@ public class RollbackRuleAttribute implements Serializable{
* for the given {@code exceptionName}.
* <p>This can be a substring, with no wildcard support at present. A value
* of "ServletException" would match
* {@code javax.servlet.ServletException} and subclasses, for example.
* {@code jakarta.servlet.ServletException} and subclasses, for example.
* <p><b>NB:</b> Consider carefully how specific the pattern is, and
* whether to include package information (which is not mandatory). For
* example, "Exception" will match nearly anything, and will probably hide

View File

@@ -18,8 +18,8 @@ package org.springframework.transaction.jta;
import java.util.List;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import jakarta.transaction.Status;
import jakarta.transaction.Synchronization;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationUtils;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2021 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.
@@ -23,17 +23,18 @@ import java.util.List;
import java.util.Properties;
import javax.naming.NamingException;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.InvalidTransactionException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.TransactionSynchronizationRegistry;
import javax.transaction.UserTransaction;
import jakarta.transaction.HeuristicMixedException;
import jakarta.transaction.HeuristicRollbackException;
import jakarta.transaction.InvalidTransactionException;
import jakarta.transaction.NotSupportedException;
import jakarta.transaction.RollbackException;
import jakarta.transaction.Status;
import jakarta.transaction.SystemException;
import jakarta.transaction.Transaction;
import jakarta.transaction.TransactionManager;
import jakarta.transaction.TransactionSynchronizationRegistry;
import jakarta.transaction.UserTransaction;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jndi.JndiTemplate;
@@ -56,7 +57,7 @@ import org.springframework.util.StringUtils;
/**
* {@link org.springframework.transaction.PlatformTransactionManager} implementation
* for JTA, delegating to a backend JTA provider. This is typically used to delegate
* to a Java EE server's transaction coordinator, but may also be configured with a
* to a Jakarta EE server's transaction coordinator, but may also be configured with a
* local JTA provider which is embedded within the application.
*
* <p>This transaction manager is appropriate for handling distributed transactions,
@@ -67,8 +68,8 @@ import org.springframework.util.StringUtils;
* HibernateTransactionManager is appropriate, for example.
*
* <p><b>For typical JTA transactions (REQUIRED, SUPPORTS, MANDATORY, NEVER), a plain
* JtaTransactionManager definition is all you need, portable across all Java EE servers.</b>
* This corresponds to the functionality of the JTA UserTransaction, for which Java EE
* JtaTransactionManager definition is all you need, portable across all Jakarta EE servers.</b>
* This corresponds to the functionality of the JTA UserTransaction, for which Jakarta EE
* specifies a standard JNDI name ("java:comp/UserTransaction"). There is no need to
* configure a server-specific TransactionManager lookup for this kind of JTA usage.
*
@@ -77,26 +78,17 @@ import org.springframework.util.StringUtils;
* autodetected by JtaTransactionManager, provided that the "autodetectTransactionManager"
* flag is set to "true" (which it is by default).
*
* <p>Note: Support for the JTA TransactionManager interface is not required by Java EE.
* Almost all Java EE servers expose it, but do so as extension to EE. There might be some
* <p>Note: Support for the JTA TransactionManager interface is not required by Jakarta EE.
* Almost all Jakarta EE servers expose it, but do so as extension to EE. There might be some
* issues with compatibility, despite the TransactionManager interface being part of JTA.
* As a consequence, Spring provides various vendor-specific PlatformTransactionManagers,
* which are recommended to be used if appropriate: {@link WebLogicJtaTransactionManager}
* and {@link WebSphereUowTransactionManager}. For all other Java EE servers, the
* standard JtaTransactionManager is sufficient.
*
* <p>This pure JtaTransactionManager class supports timeouts but not per-transaction
* isolation levels. Custom subclasses may override the {@link #doJtaBegin} method for
* specific JTA extensions in order to provide this functionality; Spring includes a
* corresponding {@link WebLogicJtaTransactionManager} class for WebLogic Server. Such
* adapters for specific Java EE transaction coordinators may also expose transaction
* names for monitoring; with standard JTA, transaction names will simply be ignored.
* specific JTA extensions in order to provide this functionality. Such adapters for
* specific Jakarta EE transaction coordinators may also expose transaction names for
* monitoring; with standard JTA, transaction names will simply be ignored.
*
* <p><b>Consider using Spring's {@code tx:jta-transaction-manager} configuration
* element for automatically picking the appropriate JTA platform transaction manager
* (automatically detecting WebLogic and WebSphere).</b>
*
* <p>JTA 1.1 adds the TransactionSynchronizationRegistry facility, as public Java EE 5
* <p>JTA 1.1 adds the TransactionSynchronizationRegistry facility, as public Jakarta EE
* API in addition to the standard JTA UserTransaction handle. As of Spring 2.5, this
* JtaTransactionManager autodetects the TransactionSynchronizationRegistry and uses
* it for registering Spring-managed synchronizations when participating in an existing
@@ -108,21 +100,20 @@ import org.springframework.util.StringUtils;
*
* @author Juergen Hoeller
* @since 24.03.2003
* @see javax.transaction.UserTransaction
* @see javax.transaction.TransactionManager
* @see javax.transaction.TransactionSynchronizationRegistry
* @see jakarta.transaction.UserTransaction
* @see jakarta.transaction.TransactionManager
* @see jakarta.transaction.TransactionSynchronizationRegistry
* @see #setUserTransactionName
* @see #setUserTransaction
* @see #setTransactionManagerName
* @see #setTransactionManager
* @see WebLogicJtaTransactionManager
*/
@SuppressWarnings("serial")
public class JtaTransactionManager extends AbstractPlatformTransactionManager
implements TransactionFactory, InitializingBean, Serializable {
/**
* Default JNDI location for the JTA UserTransaction. Many Java EE servers
* Default JNDI location for the JTA UserTransaction. Many Jakarta EE servers
* also provide support for the JTA TransactionManager interface there.
* @see #setUserTransactionName
* @see #setAutodetectTransactionManager
@@ -141,7 +132,7 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager
"java:pm/TransactionManager", "java:/TransactionManager"};
/**
* Standard Java EE 5 JNDI location for the JTA TransactionSynchronizationRegistry.
* Standard Jakarta EE JNDI location for the JTA TransactionSynchronizationRegistry.
* Autodetected when available.
*/
public static final String DEFAULT_TRANSACTION_SYNCHRONIZATION_REGISTRY_NAME =
@@ -265,7 +256,7 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager
/**
* Set the JTA UserTransaction to use as direct reference.
* <p>Typically just used for local JTA setups; in a Java EE environment,
* <p>Typically just used for local JTA setups; in a Jakarta EE environment,
* the UserTransaction will always be fetched from JNDI.
* @see #setUserTransactionName
* @see #setAutodetectUserTransaction
@@ -284,7 +275,7 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager
/**
* Set the JNDI name of the JTA UserTransaction.
* <p>Note that the UserTransaction will be autodetected at the Java EE
* <p>Note that the UserTransaction will be autodetected at the Jakarta EE
* default location "java:comp/UserTransaction" if not specified explicitly.
* @see #DEFAULT_USER_TRANSACTION_NAME
* @see #setUserTransaction
@@ -296,7 +287,7 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager
/**
* Set whether to autodetect the JTA UserTransaction at its default
* JNDI location "java:comp/UserTransaction", as specified by Java EE.
* JNDI location "java:comp/UserTransaction", as specified by Jakarta EE.
* Will proceed without UserTransaction if none found.
* <p>Default is "true", autodetecting the UserTransaction unless
* it has been specified explicitly. Turn this flag off to allow for
@@ -381,7 +372,7 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager
* <p>A TransactionSynchronizationRegistry allows for interposed registration
* of transaction synchronizations, as an alternative to the regular registration
* methods on the JTA TransactionManager API. Also, it is an official part of the
* Java EE 5 platform, in contrast to the JTA TransactionManager itself.
* Jakarta EE platform, in contrast to the JTA TransactionManager itself.
* <p>Note that the TransactionSynchronizationRegistry will be autodetected in JNDI and
* also from the UserTransaction/TransactionManager object if implemented there as well.
* @see #setTransactionSynchronizationRegistryName
@@ -402,7 +393,7 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager
/**
* Set the JNDI name of the JTA 1.1 TransactionSynchronizationRegistry.
* <p>Note that the TransactionSynchronizationRegistry will be autodetected
* at the Java EE 5 default location "java:comp/TransactionSynchronizationRegistry"
* at the Jakarta EE default location "java:comp/TransactionSynchronizationRegistry"
* if not specified explicitly.
* @see #DEFAULT_TRANSACTION_SYNCHRONIZATION_REGISTRY_NAME
*/
@@ -741,7 +732,7 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager
/**
* Find the JTA 1.1 TransactionSynchronizationRegistry through autodetection:
* checking whether the UserTransaction object or TransactionManager object
* implements it, and checking Java EE 5's standard JNDI location.
* implements it, and checking Jakarta EE's standard JNDI location.
* <p>The default implementation simply returns {@code null}.
* @param ut the JTA UserTransaction object
* @param tm the JTA TransactionManager object
@@ -834,7 +825,7 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager
* <p>JTA implementations might support nested transactions via further
* {@code UserTransaction.begin()} invocations, but never support savepoints.
* @see #doBegin
* @see javax.transaction.UserTransaction#begin()
* @see jakarta.transaction.UserTransaction#begin()
*/
@Override
protected boolean useSavepointForNestedTransaction() {
@@ -874,8 +865,8 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager
* @see #applyIsolationLevel
* @see #applyTimeout
* @see JtaTransactionObject#getUserTransaction()
* @see javax.transaction.UserTransaction#setTransactionTimeout
* @see javax.transaction.UserTransaction#begin
* @see jakarta.transaction.UserTransaction#setTransactionTimeout
* @see jakarta.transaction.UserTransaction#begin
*/
protected void doJtaBegin(JtaTransactionObject txObject, TransactionDefinition definition)
throws NotSupportedException, SystemException {
@@ -918,7 +909,7 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager
* @throws SystemException if thrown by the JTA implementation
* @see #doJtaBegin
* @see JtaTransactionObject#getUserTransaction()
* @see javax.transaction.UserTransaction#setTransactionTimeout(int)
* @see jakarta.transaction.UserTransaction#setTransactionTimeout(int)
*/
protected void applyTimeout(JtaTransactionObject txObject, int timeout) throws SystemException {
if (timeout > TransactionDefinition.TIMEOUT_DEFAULT) {
@@ -948,7 +939,7 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager
* @return the suspended JTA Transaction object
* @throws SystemException if thrown by JTA methods
* @see #getTransactionManager()
* @see javax.transaction.TransactionManager#suspend()
* @see jakarta.transaction.TransactionManager#suspend()
*/
protected Object doJtaSuspend(JtaTransactionObject txObject) throws SystemException {
if (getTransactionManager() == null) {
@@ -984,7 +975,7 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager
* @throws InvalidTransactionException if thrown by JTA methods
* @throws SystemException if thrown by JTA methods
* @see #getTransactionManager()
* @see javax.transaction.TransactionManager#resume(javax.transaction.Transaction)
* @see jakarta.transaction.TransactionManager#resume(jakarta.transaction.Transaction)
*/
protected void doJtaResume(@Nullable JtaTransactionObject txObject, Object suspendedTransaction)
throws InvalidTransactionException, SystemException {
@@ -1144,8 +1135,8 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager
* @throws RollbackException if thrown by JTA methods
* @throws SystemException if thrown by JTA methods
* @see #getTransactionManager()
* @see javax.transaction.Transaction#registerSynchronization
* @see javax.transaction.TransactionSynchronizationRegistry#registerInterposedSynchronization
* @see jakarta.transaction.Transaction#registerSynchronization
* @see jakarta.transaction.TransactionSynchronizationRegistry#registerInterposedSynchronization
*/
protected void doRegisterAfterCompletionWithJtaTransaction(
JtaTransactionObject txObject, List<TransactionSynchronization> synchronizations)

View File

@@ -16,16 +16,16 @@
package org.springframework.transaction.jta;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
import jakarta.transaction.Status;
import jakarta.transaction.SystemException;
import jakarta.transaction.UserTransaction;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.transaction.support.SmartTransactionObject;
import org.springframework.transaction.support.TransactionSynchronizationUtils;
/**
* JTA transaction object, representing a {@link javax.transaction.UserTransaction}.
* JTA transaction object, representing a {@link jakarta.transaction.UserTransaction}.
* Used as transaction object by Spring's {@link JtaTransactionManager}.
*
* <p>Note: This is an SPI class, not intended to be used by applications.
@@ -33,7 +33,7 @@ import org.springframework.transaction.support.TransactionSynchronizationUtils;
* @author Juergen Hoeller
* @since 1.1
* @see JtaTransactionManager
* @see javax.transaction.UserTransaction
* @see jakarta.transaction.UserTransaction
*/
public class JtaTransactionObject implements SmartTransactionObject {

View File

@@ -16,21 +16,22 @@
package org.springframework.transaction.jta;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.RollbackException;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.xa.XAResource;
import jakarta.transaction.HeuristicMixedException;
import jakarta.transaction.HeuristicRollbackException;
import jakarta.transaction.RollbackException;
import jakarta.transaction.Synchronization;
import jakarta.transaction.SystemException;
import jakarta.transaction.Transaction;
import jakarta.transaction.TransactionManager;
import org.springframework.util.Assert;
/**
* Adapter for a managed JTA Transaction handle, taking a JTA
* {@link javax.transaction.TransactionManager} reference and creating
* a JTA {@link javax.transaction.Transaction} handle for it.
* {@link jakarta.transaction.TransactionManager} reference and creating
* a JTA {@link jakarta.transaction.Transaction} handle for it.
*
* @author Juergen Hoeller
* @since 3.0.2

View File

@@ -16,25 +16,25 @@
package org.springframework.transaction.jta;
import javax.transaction.NotSupportedException;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import jakarta.transaction.NotSupportedException;
import jakarta.transaction.SystemException;
import jakarta.transaction.Transaction;
import jakarta.transaction.TransactionManager;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Default implementation of the {@link TransactionFactory} strategy interface,
* simply wrapping a standard JTA {@link javax.transaction.TransactionManager}.
* simply wrapping a standard JTA {@link jakarta.transaction.TransactionManager}.
*
* <p>Does not support transaction names; simply ignores any specified name.
*
* @author Juergen Hoeller
* @since 2.5
* @see javax.transaction.TransactionManager#setTransactionTimeout(int)
* @see javax.transaction.TransactionManager#begin()
* @see javax.transaction.TransactionManager#getTransaction()
* @see jakarta.transaction.TransactionManager#setTransactionTimeout(int)
* @see jakarta.transaction.TransactionManager#begin()
* @see jakarta.transaction.TransactionManager#getTransaction()
*/
public class SimpleTransactionFactory implements TransactionFactory {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2021 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.
@@ -16,11 +16,10 @@
package org.springframework.transaction.jta;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import jakarta.transaction.Status;
import jakarta.transaction.Synchronization;
import jakarta.transaction.TransactionManager;
import jakarta.transaction.UserTransaction;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -30,7 +29,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
import org.springframework.util.Assert;
/**
* Adapter that implements the JTA {@link javax.transaction.Synchronization}
* Adapter that implements the JTA {@link jakarta.transaction.Synchronization}
* interface delegating to an underlying Spring
* {@link org.springframework.transaction.support.TransactionSynchronization}.
*
@@ -40,7 +39,7 @@ import org.springframework.util.Assert;
*
* @author Juergen Hoeller
* @since 2.0
* @see javax.transaction.Transaction#registerSynchronization
* @see jakarta.transaction.Transaction#registerSynchronization
* @see org.springframework.transaction.support.TransactionSynchronization
*/
public class SpringJtaSynchronizationAdapter implements Synchronization {
@@ -82,9 +81,7 @@ public class SpringJtaSynchronizationAdapter implements Synchronization {
@Nullable UserTransaction jtaUserTransaction) {
this(springSynchronization);
if (jtaUserTransaction != null && !jtaUserTransaction.getClass().getName().startsWith("weblogic.")) {
this.jtaTransaction = jtaUserTransaction;
}
this.jtaTransaction = jtaUserTransaction;
}
/**
@@ -104,9 +101,7 @@ public class SpringJtaSynchronizationAdapter implements Synchronization {
TransactionSynchronization springSynchronization, @Nullable TransactionManager jtaTransactionManager) {
this(springSynchronization);
if (jtaTransactionManager != null && !jtaTransactionManager.getClass().getName().startsWith("weblogic.")) {
this.jtaTransaction = new UserTransactionAdapter(jtaTransactionManager);
}
this.jtaTransaction = new UserTransactionAdapter(jtaTransactionManager);
}

View File

@@ -16,24 +16,24 @@
package org.springframework.transaction.jta;
import javax.transaction.NotSupportedException;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import jakarta.transaction.NotSupportedException;
import jakarta.transaction.SystemException;
import jakarta.transaction.Transaction;
import org.springframework.lang.Nullable;
/**
* Strategy interface for creating JTA {@link javax.transaction.Transaction}
* Strategy interface for creating JTA {@link jakarta.transaction.Transaction}
* objects based on specified transactional characteristics.
*
* <p>The default implementation, {@link SimpleTransactionFactory}, simply
* wraps a standard JTA {@link javax.transaction.TransactionManager}.
* wraps a standard JTA {@link jakarta.transaction.TransactionManager}.
* This strategy interface allows for more sophisticated implementations
* that adapt to vendor-specific JTA extensions.
*
* @author Juergen Hoeller
* @since 2.5
* @see javax.transaction.TransactionManager#getTransaction()
* @see jakarta.transaction.TransactionManager#getTransaction()
* @see SimpleTransactionFactory
* @see JtaTransactionManager
*/
@@ -58,8 +58,8 @@ public interface TransactionFactory {
* {@link org.springframework.jca.endpoint.AbstractMessageEndpointFactory}
* in order to differentiate between invalid configuration and valid
* ResourceAdapter-managed transactions.
* @see javax.resource.spi.ResourceAdapter#endpointActivation
* @see javax.resource.spi.endpoint.MessageEndpointFactory#isDeliveryTransacted
* @see jakarta.resource.spi.ResourceAdapter#endpointActivation
* @see jakarta.resource.spi.endpoint.MessageEndpointFactory#isDeliveryTransacted
*/
boolean supportsResourceAdapterManagedTransactions();

View File

@@ -16,20 +16,20 @@
package org.springframework.transaction.jta;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import jakarta.transaction.HeuristicMixedException;
import jakarta.transaction.HeuristicRollbackException;
import jakarta.transaction.NotSupportedException;
import jakarta.transaction.RollbackException;
import jakarta.transaction.SystemException;
import jakarta.transaction.TransactionManager;
import jakarta.transaction.UserTransaction;
import org.springframework.util.Assert;
/**
* Adapter for a JTA UserTransaction handle, taking a JTA
* {@link javax.transaction.TransactionManager} reference and creating
* a JTA {@link javax.transaction.UserTransaction} handle for it.
* {@link jakarta.transaction.TransactionManager} reference and creating
* a JTA {@link jakarta.transaction.UserTransaction} handle for it.
*
* <p>The JTA UserTransaction interface is an exact subset of the JTA
* TransactionManager interface. Unfortunately, it does not serve as

View File

@@ -1,366 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.transaction.jta;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.transaction.InvalidTransactionException;
import javax.transaction.NotSupportedException;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import org.springframework.lang.Nullable;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.util.Assert;
/**
* Special {@link JtaTransactionManager} variant for BEA WebLogic (9.0 and higher).
* Supports the full power of Spring's transaction definitions on WebLogic's
* transaction coordinator, <i>beyond standard JTA</i>: transaction names,
* per-transaction isolation levels, and proper resuming of transactions in all cases.
*
* <p>Uses WebLogic's special {@code begin(name)} method to start a JTA transaction,
* in order to make <b>Spring-driven transactions visible in WebLogic's transaction
* monitor</b>. In case of Spring's declarative transactions, the exposed name will
* (by default) be the fully-qualified class name + "." + method name.
*
* <p>Supports a <b>per-transaction isolation level</b> through WebLogic's corresponding
* JTA transaction property "ISOLATION LEVEL". This will apply the specified isolation
* level (e.g. ISOLATION_SERIALIZABLE) to all JDBC Connections that participate in the
* given transaction.
*
* <p>Invokes WebLogic's special {@code forceResume} method if standard JTA resume
* failed, to <b>also resume if the target transaction was marked rollback-only</b>.
* If you're not relying on this feature of transaction suspension in the first
* place, Spring's standard JtaTransactionManager will behave properly too.
*
* <p>By default, the JTA UserTransaction and TransactionManager handles are
* fetched directly from WebLogic's {@code TransactionHelper}. This can be
* overridden by specifying "userTransaction"/"userTransactionName" and
* "transactionManager"/"transactionManagerName", passing in existing handles
* or specifying corresponding JNDI locations to look up.
*
* <p><b>NOTE: This JtaTransactionManager is intended to refine specific transaction
* demarcation behavior on Spring's side. It will happily co-exist with independently
* configured WebLogic transaction strategies in your persistence provider, with no
* need to specifically connect those setups in any way.</b>
*
* @author Juergen Hoeller
* @since 1.1
* @see org.springframework.transaction.TransactionDefinition#getName
* @see org.springframework.transaction.TransactionDefinition#getIsolationLevel
* @see weblogic.transaction.UserTransaction#begin(String)
* @see weblogic.transaction.Transaction#setProperty
* @see weblogic.transaction.TransactionManager#forceResume
* @see weblogic.transaction.TransactionHelper
*/
@SuppressWarnings("serial")
public class WebLogicJtaTransactionManager extends JtaTransactionManager {
private static final String USER_TRANSACTION_CLASS_NAME = "weblogic.transaction.UserTransaction";
private static final String CLIENT_TRANSACTION_MANAGER_CLASS_NAME = "weblogic.transaction.ClientTransactionManager";
private static final String TRANSACTION_CLASS_NAME = "weblogic.transaction.Transaction";
private static final String TRANSACTION_HELPER_CLASS_NAME = "weblogic.transaction.TransactionHelper";
private static final String ISOLATION_LEVEL_KEY = "ISOLATION LEVEL";
private boolean weblogicUserTransactionAvailable;
@Nullable
private Method beginWithNameMethod;
@Nullable
private Method beginWithNameAndTimeoutMethod;
private boolean weblogicTransactionManagerAvailable;
@Nullable
private Method forceResumeMethod;
@Nullable
private Method setPropertyMethod;
@Nullable
private Object transactionHelper;
@Override
public void afterPropertiesSet() throws TransactionSystemException {
super.afterPropertiesSet();
loadWebLogicTransactionClasses();
}
@Override
@Nullable
protected UserTransaction retrieveUserTransaction() throws TransactionSystemException {
Object helper = loadWebLogicTransactionHelper();
try {
logger.trace("Retrieving JTA UserTransaction from WebLogic TransactionHelper");
Method getUserTransactionMethod = helper.getClass().getMethod("getUserTransaction");
return (UserTransaction) getUserTransactionMethod.invoke(this.transactionHelper);
}
catch (InvocationTargetException ex) {
throw new TransactionSystemException(
"WebLogic's TransactionHelper.getUserTransaction() method failed", ex.getTargetException());
}
catch (Exception ex) {
throw new TransactionSystemException(
"Could not invoke WebLogic's TransactionHelper.getUserTransaction() method", ex);
}
}
@Override
@Nullable
protected TransactionManager retrieveTransactionManager() throws TransactionSystemException {
Object helper = loadWebLogicTransactionHelper();
try {
logger.trace("Retrieving JTA TransactionManager from WebLogic TransactionHelper");
Method getTransactionManagerMethod = helper.getClass().getMethod("getTransactionManager");
return (TransactionManager) getTransactionManagerMethod.invoke(this.transactionHelper);
}
catch (InvocationTargetException ex) {
throw new TransactionSystemException(
"WebLogic's TransactionHelper.getTransactionManager() method failed", ex.getTargetException());
}
catch (Exception ex) {
throw new TransactionSystemException(
"Could not invoke WebLogic's TransactionHelper.getTransactionManager() method", ex);
}
}
private Object loadWebLogicTransactionHelper() throws TransactionSystemException {
Object helper = this.transactionHelper;
if (helper == null) {
try {
Class<?> transactionHelperClass = getClass().getClassLoader().loadClass(TRANSACTION_HELPER_CLASS_NAME);
Method getTransactionHelperMethod = transactionHelperClass.getMethod("getTransactionHelper");
helper = getTransactionHelperMethod.invoke(null);
this.transactionHelper = helper;
logger.trace("WebLogic TransactionHelper found");
}
catch (InvocationTargetException ex) {
throw new TransactionSystemException(
"WebLogic's TransactionHelper.getTransactionHelper() method failed", ex.getTargetException());
}
catch (Exception ex) {
throw new TransactionSystemException(
"Could not initialize WebLogicJtaTransactionManager because WebLogic API classes are not available",
ex);
}
}
return helper;
}
private void loadWebLogicTransactionClasses() throws TransactionSystemException {
try {
Class<?> userTransactionClass = getClass().getClassLoader().loadClass(USER_TRANSACTION_CLASS_NAME);
this.weblogicUserTransactionAvailable = userTransactionClass.isInstance(getUserTransaction());
if (this.weblogicUserTransactionAvailable) {
this.beginWithNameMethod = userTransactionClass.getMethod("begin", String.class);
this.beginWithNameAndTimeoutMethod = userTransactionClass.getMethod("begin", String.class, int.class);
logger.debug("Support for WebLogic transaction names available");
}
else {
logger.debug("Support for WebLogic transaction names not available");
}
// Obtain WebLogic ClientTransactionManager interface.
Class<?> transactionManagerClass =
getClass().getClassLoader().loadClass(CLIENT_TRANSACTION_MANAGER_CLASS_NAME);
logger.trace("WebLogic ClientTransactionManager found");
this.weblogicTransactionManagerAvailable = transactionManagerClass.isInstance(getTransactionManager());
if (this.weblogicTransactionManagerAvailable) {
Class<?> transactionClass = getClass().getClassLoader().loadClass(TRANSACTION_CLASS_NAME);
this.forceResumeMethod = transactionManagerClass.getMethod("forceResume", Transaction.class);
this.setPropertyMethod = transactionClass.getMethod("setProperty", String.class, Serializable.class);
logger.debug("Support for WebLogic forceResume available");
}
else {
logger.debug("Support for WebLogic forceResume not available");
}
}
catch (Exception ex) {
throw new TransactionSystemException(
"Could not initialize WebLogicJtaTransactionManager because WebLogic API classes are not available",
ex);
}
}
private TransactionManager obtainTransactionManager() {
TransactionManager tm = getTransactionManager();
Assert.state(tm != null, "No TransactionManager set");
return tm;
}
@Override
protected void doJtaBegin(JtaTransactionObject txObject, TransactionDefinition definition)
throws NotSupportedException, SystemException {
int timeout = determineTimeout(definition);
// Apply transaction name (if any) to WebLogic transaction.
if (this.weblogicUserTransactionAvailable && definition.getName() != null) {
try {
if (timeout > TransactionDefinition.TIMEOUT_DEFAULT) {
/*
weblogic.transaction.UserTransaction wut = (weblogic.transaction.UserTransaction) ut;
wut.begin(definition.getName(), timeout);
*/
Assert.state(this.beginWithNameAndTimeoutMethod != null, "WebLogic JTA API not initialized");
this.beginWithNameAndTimeoutMethod.invoke(txObject.getUserTransaction(), definition.getName(), timeout);
}
else {
/*
weblogic.transaction.UserTransaction wut = (weblogic.transaction.UserTransaction) ut;
wut.begin(definition.getName());
*/
Assert.state(this.beginWithNameMethod != null, "WebLogic JTA API not initialized");
this.beginWithNameMethod.invoke(txObject.getUserTransaction(), definition.getName());
}
}
catch (InvocationTargetException ex) {
throw new TransactionSystemException(
"WebLogic's UserTransaction.begin() method failed", ex.getTargetException());
}
catch (Exception ex) {
throw new TransactionSystemException(
"Could not invoke WebLogic's UserTransaction.begin() method", ex);
}
}
else {
// No WebLogic UserTransaction available or no transaction name specified
// -> standard JTA begin call.
applyTimeout(txObject, timeout);
txObject.getUserTransaction().begin();
}
// Specify isolation level, if any, through corresponding WebLogic transaction property.
if (this.weblogicTransactionManagerAvailable) {
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
try {
Transaction tx = obtainTransactionManager().getTransaction();
Integer isolationLevel = definition.getIsolationLevel();
/*
weblogic.transaction.Transaction wtx = (weblogic.transaction.Transaction) tx;
wtx.setProperty(ISOLATION_LEVEL_KEY, isolationLevel);
*/
Assert.state(this.setPropertyMethod != null, "WebLogic JTA API not initialized");
this.setPropertyMethod.invoke(tx, ISOLATION_LEVEL_KEY, isolationLevel);
}
catch (InvocationTargetException ex) {
throw new TransactionSystemException(
"WebLogic's Transaction.setProperty(String, Serializable) method failed", ex.getTargetException());
}
catch (Exception ex) {
throw new TransactionSystemException(
"Could not invoke WebLogic's Transaction.setProperty(String, Serializable) method", ex);
}
}
}
else {
applyIsolationLevel(txObject, definition.getIsolationLevel());
}
}
@Override
protected void doJtaResume(@Nullable JtaTransactionObject txObject, Object suspendedTransaction)
throws InvalidTransactionException, SystemException {
try {
obtainTransactionManager().resume((Transaction) suspendedTransaction);
}
catch (InvalidTransactionException ex) {
if (!this.weblogicTransactionManagerAvailable) {
throw ex;
}
if (logger.isDebugEnabled()) {
logger.debug("Standard JTA resume threw InvalidTransactionException: " + ex.getMessage() +
" - trying WebLogic JTA forceResume");
}
/*
weblogic.transaction.TransactionManager wtm =
(weblogic.transaction.TransactionManager) getTransactionManager();
wtm.forceResume(suspendedTransaction);
*/
try {
Assert.state(this.forceResumeMethod != null, "WebLogic JTA API not initialized");
this.forceResumeMethod.invoke(getTransactionManager(), suspendedTransaction);
}
catch (InvocationTargetException ex2) {
throw new TransactionSystemException(
"WebLogic's TransactionManager.forceResume(Transaction) method failed", ex2.getTargetException());
}
catch (Exception ex2) {
throw new TransactionSystemException(
"Could not access WebLogic's TransactionManager.forceResume(Transaction) method", ex2);
}
}
}
@Override
public Transaction createTransaction(@Nullable String name, int timeout) throws NotSupportedException, SystemException {
if (this.weblogicUserTransactionAvailable && name != null) {
try {
if (timeout >= 0) {
Assert.state(this.beginWithNameAndTimeoutMethod != null, "WebLogic JTA API not initialized");
this.beginWithNameAndTimeoutMethod.invoke(getUserTransaction(), name, timeout);
}
else {
Assert.state(this.beginWithNameMethod != null, "WebLogic JTA API not initialized");
this.beginWithNameMethod.invoke(getUserTransaction(), name);
}
}
catch (InvocationTargetException ex) {
if (ex.getTargetException() instanceof NotSupportedException) {
throw (NotSupportedException) ex.getTargetException();
}
else if (ex.getTargetException() instanceof SystemException) {
throw (SystemException) ex.getTargetException();
}
else if (ex.getTargetException() instanceof RuntimeException) {
throw (RuntimeException) ex.getTargetException();
}
else {
throw new SystemException(
"WebLogic's begin() method failed with an unexpected error: " + ex.getTargetException());
}
}
catch (Exception ex) {
throw new SystemException("Could not invoke WebLogic's UserTransaction.begin() method: " + ex);
}
return new ManagedTransactionAdapter(obtainTransactionManager());
}
else {
// No name specified - standard JTA is sufficient.
return super.createTransaction(name, timeout);
}
}
}

View File

@@ -1,423 +0,0 @@
/*
* Copyright 2002-2020 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
*
* https://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.transaction.jta;
import java.util.List;
import javax.naming.NamingException;
import com.ibm.websphere.uow.UOWSynchronizationRegistry;
import com.ibm.wsspi.uow.UOWAction;
import com.ibm.wsspi.uow.UOWActionException;
import com.ibm.wsspi.uow.UOWException;
import com.ibm.wsspi.uow.UOWManager;
import com.ibm.wsspi.uow.UOWManagerFactory;
import org.springframework.lang.Nullable;
import org.springframework.transaction.IllegalTransactionStateException;
import org.springframework.transaction.InvalidTimeoutException;
import org.springframework.transaction.NestedTransactionNotSupportedException;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;
import org.springframework.transaction.support.SmartTransactionObject;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionSynchronizationUtils;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
/**
* WebSphere-specific PlatformTransactionManager implementation that delegates
* to a {@link com.ibm.wsspi.uow.UOWManager} instance, obtained from WebSphere's
* JNDI environment. This allows Spring to leverage the full power of the WebSphere
* transaction coordinator, including transaction suspension, in a manner that is
* perfectly compliant with officially supported WebSphere API.
*
* <p>The {@link CallbackPreferringPlatformTransactionManager} interface
* implemented by this class indicates that callers should preferably pass in
* a {@link TransactionCallback} through the {@link #execute} method, which
* will be handled through the callback-based WebSphere UOWManager API instead
* of through standard JTA API (UserTransaction / TransactionManager). This avoids
* the use of the non-public {@code javax.transaction.TransactionManager}
* API on WebSphere, staying within supported WebSphere API boundaries.
*
* <p>This transaction manager implementation derives from Spring's standard
* {@link JtaTransactionManager}, inheriting the capability to support programmatic
* transaction demarcation via {@code getTransaction} / {@code commit} /
* {@code rollback} calls through a JTA UserTransaction handle, for callers
* that do not use the TransactionCallback-based {@link #execute} method. However,
* transaction suspension is <i>not</i> supported in this {@code getTransaction}
* style (unless you explicitly specify a {@link #setTransactionManager} reference,
* despite the official WebSphere recommendations). Use the {@link #execute} style
* for any code that might require transaction suspension.
*
* <p>This transaction manager is compatible with WebSphere 6.1.0.9 and above.
* The default JNDI location for the UOWManager is "java:comp/websphere/UOWManager".
* If the location happens to differ according to your WebSphere documentation,
* simply specify the actual location through this transaction manager's
* "uowManagerName" bean property.
*
* <p><b>NOTE: This JtaTransactionManager is intended to refine specific transaction
* demarcation behavior on Spring's side. It will happily co-exist with independently
* configured WebSphere transaction strategies in your persistence provider, with no
* need to specifically connect those setups in any way.</b>
*
* @author Juergen Hoeller
* @since 2.5
* @see #setUowManager
* @see #setUowManagerName
* @see com.ibm.wsspi.uow.UOWManager
*/
@SuppressWarnings("serial")
public class WebSphereUowTransactionManager extends JtaTransactionManager
implements CallbackPreferringPlatformTransactionManager {
/**
* Default JNDI location for the WebSphere UOWManager.
* @see #setUowManagerName
*/
public static final String DEFAULT_UOW_MANAGER_NAME = "java:comp/websphere/UOWManager";
@Nullable
private UOWManager uowManager;
@Nullable
private String uowManagerName;
/**
* Create a new WebSphereUowTransactionManager.
*/
public WebSphereUowTransactionManager() {
setAutodetectTransactionManager(false);
}
/**
* Create a new WebSphereUowTransactionManager for the given UOWManager.
* @param uowManager the WebSphere UOWManager to use as direct reference
*/
public WebSphereUowTransactionManager(UOWManager uowManager) {
this();
this.uowManager = uowManager;
}
/**
* Set the WebSphere UOWManager to use as direct reference.
* <p>Typically just used for test setups; in a Java EE environment,
* the UOWManager will always be fetched from JNDI.
* @see #setUserTransactionName
*/
public void setUowManager(UOWManager uowManager) {
this.uowManager = uowManager;
}
/**
* Set the JNDI name of the WebSphere UOWManager.
* The default "java:comp/websphere/UOWManager" is used if not set.
* @see #DEFAULT_USER_TRANSACTION_NAME
* @see #setUowManager
*/
public void setUowManagerName(String uowManagerName) {
this.uowManagerName = uowManagerName;
}
@Override
public void afterPropertiesSet() throws TransactionSystemException {
initUserTransactionAndTransactionManager();
// Fetch UOWManager handle from JNDI, if necessary.
if (this.uowManager == null) {
if (this.uowManagerName != null) {
this.uowManager = lookupUowManager(this.uowManagerName);
}
else {
this.uowManager = lookupDefaultUowManager();
}
}
}
/**
* Look up the WebSphere UOWManager in JNDI via the configured name.
* @param uowManagerName the JNDI name of the UOWManager
* @return the UOWManager object
* @throws TransactionSystemException if the JNDI lookup failed
* @see #setJndiTemplate
* @see #setUowManagerName
*/
protected UOWManager lookupUowManager(String uowManagerName) throws TransactionSystemException {
try {
if (logger.isDebugEnabled()) {
logger.debug("Retrieving WebSphere UOWManager from JNDI location [" + uowManagerName + "]");
}
return getJndiTemplate().lookup(uowManagerName, UOWManager.class);
}
catch (NamingException ex) {
throw new TransactionSystemException(
"WebSphere UOWManager is not available at JNDI location [" + uowManagerName + "]", ex);
}
}
/**
* Obtain the WebSphere UOWManager from the default JNDI location
* "java:comp/websphere/UOWManager".
* @return the UOWManager object
* @throws TransactionSystemException if the JNDI lookup failed
* @see #setJndiTemplate
*/
protected UOWManager lookupDefaultUowManager() throws TransactionSystemException {
try {
logger.debug("Retrieving WebSphere UOWManager from default JNDI location [" + DEFAULT_UOW_MANAGER_NAME + "]");
return getJndiTemplate().lookup(DEFAULT_UOW_MANAGER_NAME, UOWManager.class);
}
catch (NamingException ex) {
logger.debug("WebSphere UOWManager is not available at default JNDI location [" +
DEFAULT_UOW_MANAGER_NAME + "] - falling back to UOWManagerFactory lookup");
return UOWManagerFactory.getUOWManager();
}
}
private UOWManager obtainUOWManager() {
Assert.state(this.uowManager != null, "No UOWManager set");
return this.uowManager;
}
/**
* Registers the synchronizations as interposed JTA Synchronization on the UOWManager.
*/
@Override
protected void doRegisterAfterCompletionWithJtaTransaction(
JtaTransactionObject txObject, List<TransactionSynchronization> synchronizations) {
obtainUOWManager().registerInterposedSynchronization(new JtaAfterCompletionSynchronization(synchronizations));
}
/**
* Returns {@code true} since WebSphere ResourceAdapters (as exposed in JNDI)
* implicitly perform transaction enlistment if the MessageEndpointFactory's
* {@code isDeliveryTransacted} method returns {@code true}.
* In that case we'll simply skip the {@link #createTransaction} call.
* @see javax.resource.spi.endpoint.MessageEndpointFactory#isDeliveryTransacted
* @see org.springframework.jca.endpoint.AbstractMessageEndpointFactory
* @see TransactionFactory#createTransaction
*/
@Override
public boolean supportsResourceAdapterManagedTransactions() {
return true;
}
@Override
@Nullable
public <T> T execute(@Nullable TransactionDefinition definition, TransactionCallback<T> callback)
throws TransactionException {
// Use defaults if no transaction definition given.
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
UOWManager uowManager = obtainUOWManager();
int pb = def.getPropagationBehavior();
boolean existingTx = (uowManager.getUOWStatus() != UOWSynchronizationRegistry.UOW_STATUS_NONE &&
uowManager.getUOWType() != UOWSynchronizationRegistry.UOW_TYPE_LOCAL_TRANSACTION);
int uowType = UOWSynchronizationRegistry.UOW_TYPE_GLOBAL_TRANSACTION;
boolean joinTx = false;
boolean newSynch = false;
if (existingTx) {
if (pb == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Transaction propagation 'never' but existing transaction found");
}
if (pb == TransactionDefinition.PROPAGATION_NESTED) {
throw new NestedTransactionNotSupportedException(
"Transaction propagation 'nested' not supported for WebSphere UOW transactions");
}
if (pb == TransactionDefinition.PROPAGATION_SUPPORTS ||
pb == TransactionDefinition.PROPAGATION_REQUIRED ||
pb == TransactionDefinition.PROPAGATION_MANDATORY) {
joinTx = true;
newSynch = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
}
else if (pb == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
uowType = UOWSynchronizationRegistry.UOW_TYPE_LOCAL_TRANSACTION;
newSynch = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
}
else {
newSynch = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
}
}
else {
if (pb == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"Transaction propagation 'mandatory' but no existing transaction found");
}
if (pb == TransactionDefinition.PROPAGATION_SUPPORTS ||
pb == TransactionDefinition.PROPAGATION_NOT_SUPPORTED ||
pb == TransactionDefinition.PROPAGATION_NEVER) {
uowType = UOWSynchronizationRegistry.UOW_TYPE_LOCAL_TRANSACTION;
newSynch = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
}
else {
newSynch = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
}
}
boolean debug = logger.isDebugEnabled();
if (debug) {
logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
SuspendedResourcesHolder suspendedResources = (!joinTx ? suspend(null) : null);
UOWActionAdapter<T> action = null;
try {
boolean actualTransaction = (uowType == UOWManager.UOW_TYPE_GLOBAL_TRANSACTION);
if (actualTransaction && def.getTimeout() > TransactionDefinition.TIMEOUT_DEFAULT) {
uowManager.setUOWTimeout(uowType, def.getTimeout());
}
if (debug) {
logger.debug("Invoking WebSphere UOW action: type=" + uowType + ", join=" + joinTx);
}
action = new UOWActionAdapter<>(def, callback, actualTransaction, !joinTx, newSynch, debug);
uowManager.runUnderUOW(uowType, joinTx, action);
if (debug) {
logger.debug("Returned from WebSphere UOW action: type=" + uowType + ", join=" + joinTx);
}
return action.getResult();
}
catch (UOWException | UOWActionException ex) {
TransactionSystemException tse =
new TransactionSystemException("UOWManager transaction processing failed", ex);
Throwable appEx = action.getException();
if (appEx != null) {
logger.error("Application exception overridden by rollback exception", appEx);
tse.initApplicationException(appEx);
}
throw tse;
}
finally {
if (suspendedResources != null) {
resume(null, suspendedResources);
}
}
}
/**
* Adapter that executes the given Spring transaction within the WebSphere UOWAction shape.
*/
private class UOWActionAdapter<T> implements UOWAction, SmartTransactionObject {
private final TransactionDefinition definition;
private final TransactionCallback<T> callback;
private final boolean actualTransaction;
private final boolean newTransaction;
private final boolean newSynchronization;
private boolean debug;
@Nullable
private T result;
@Nullable
private Throwable exception;
public UOWActionAdapter(TransactionDefinition definition, TransactionCallback<T> callback,
boolean actualTransaction, boolean newTransaction, boolean newSynchronization, boolean debug) {
this.definition = definition;
this.callback = callback;
this.actualTransaction = actualTransaction;
this.newTransaction = newTransaction;
this.newSynchronization = newSynchronization;
this.debug = debug;
}
@Override
public void run() {
UOWManager uowManager = obtainUOWManager();
DefaultTransactionStatus status = prepareTransactionStatus(
this.definition, (this.actualTransaction ? this : null),
this.newTransaction, this.newSynchronization, this.debug, null);
try {
this.result = this.callback.doInTransaction(status);
triggerBeforeCommit(status);
}
catch (Throwable ex) {
this.exception = ex;
if (status.isDebug()) {
logger.debug("Rolling back on application exception from transaction callback", ex);
}
uowManager.setRollbackOnly();
}
finally {
if (status.isLocalRollbackOnly()) {
if (status.isDebug()) {
logger.debug("Transaction callback has explicitly requested rollback");
}
uowManager.setRollbackOnly();
}
triggerBeforeCompletion(status);
if (status.isNewSynchronization()) {
List<TransactionSynchronization> synchronizations = TransactionSynchronizationManager.getSynchronizations();
TransactionSynchronizationManager.clear();
if (!synchronizations.isEmpty()) {
uowManager.registerInterposedSynchronization(new JtaAfterCompletionSynchronization(synchronizations));
}
}
}
}
@Nullable
public T getResult() {
if (this.exception != null) {
ReflectionUtils.rethrowRuntimeException(this.exception);
}
return this.result;
}
@Nullable
public Throwable getException() {
return this.exception;
}
@Override
public boolean isRollbackOnly() {
return obtainUOWManager().getRollbackOnly();
}
@Override
public void flush() {
TransactionSynchronizationUtils.triggerFlush();
}
}
}

View File

@@ -1152,8 +1152,8 @@ public abstract class AbstractPlatformTransactionManager implements PlatformTran
* @see DefaultTransactionStatus#isLocalRollbackOnly()
* @see org.springframework.transaction.TransactionStatus#setRollbackOnly()
* @see org.springframework.transaction.UnexpectedRollbackException
* @see javax.transaction.UserTransaction#commit()
* @see javax.transaction.RollbackException
* @see jakarta.transaction.UserTransaction#commit()
* @see jakarta.transaction.RollbackException
*/
protected boolean shouldCommitOnGlobalRollbackOnly() {
return false;

View File

@@ -36,8 +36,8 @@ public interface SmartTransactionObject extends Flushable {
/**
* Return whether the transaction is internally marked as rollback-only.
* Can, for example, check the JTA UserTransaction.
* @see javax.transaction.UserTransaction#getStatus
* @see javax.transaction.Status#STATUS_MARKED_ROLLBACK
* @see jakarta.transaction.UserTransaction#getStatus
* @see jakarta.transaction.Status#STATUS_MARKED_ROLLBACK
*/
boolean isRollbackOnly();