30 changed files with 55 additions and 4358 deletions
@ -1,272 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2013 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo; |
|
||||||
|
|
||||||
import java.sql.Connection; |
|
||||||
import java.sql.SQLException; |
|
||||||
import javax.jdo.Constants; |
|
||||||
import javax.jdo.JDOException; |
|
||||||
import javax.jdo.PersistenceManager; |
|
||||||
import javax.jdo.Transaction; |
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException; |
|
||||||
import org.springframework.dao.support.PersistenceExceptionTranslator; |
|
||||||
import org.springframework.jdbc.datasource.ConnectionHandle; |
|
||||||
import org.springframework.jdbc.support.JdbcUtils; |
|
||||||
import org.springframework.jdbc.support.SQLExceptionTranslator; |
|
||||||
import org.springframework.transaction.TransactionDefinition; |
|
||||||
import org.springframework.transaction.TransactionException; |
|
||||||
|
|
||||||
/** |
|
||||||
* Default implementation of the {@link JdoDialect} interface. |
|
||||||
* As of Spring 4.0, designed for JDO 3.0 (or rather, semantics beyond JDO 3.0). |
|
||||||
* Used as default dialect by {@link JdoTransactionManager}. |
|
||||||
* |
|
||||||
* <p>Simply begins a standard JDO transaction in {@code beginTransaction}. |
|
||||||
* Returns a handle for a JDO DataStoreConnection on {@code getJdbcConnection}. |
|
||||||
* Calls the corresponding JDO PersistenceManager operation on {@code flush} |
|
||||||
* Uses a Spring SQLExceptionTranslator for exception translation, if applicable. |
|
||||||
* |
|
||||||
* <p>Note that, even with JDO 3.0, vendor-specific subclasses are still necessary |
|
||||||
* for special transaction semantics and more sophisticated exception translation. |
|
||||||
* Furthermore, vendor-specific subclasses are encouraged to expose the native JDBC |
|
||||||
* Connection on {@code getJdbcConnection}, rather than JDO 3.0's wrapper handle. |
|
||||||
* |
|
||||||
* <p>This class also implements the PersistenceExceptionTranslator interface, |
|
||||||
* as autodetected by Spring's PersistenceExceptionTranslationPostProcessor, |
|
||||||
* for AOP-based translation of native exceptions to Spring DataAccessExceptions. |
|
||||||
* Hence, the presence of a standard DefaultJdoDialect bean automatically enables |
|
||||||
* a PersistenceExceptionTranslationPostProcessor to translate JDO exceptions. |
|
||||||
* |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @since 1.1 |
|
||||||
* @see #setJdbcExceptionTranslator |
|
||||||
* @see JdoTransactionManager#setJdoDialect |
|
||||||
* @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor |
|
||||||
*/ |
|
||||||
public class DefaultJdoDialect implements JdoDialect, PersistenceExceptionTranslator { |
|
||||||
|
|
||||||
private SQLExceptionTranslator jdbcExceptionTranslator; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Create a new DefaultJdoDialect. |
|
||||||
*/ |
|
||||||
public DefaultJdoDialect() { |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Create a new DefaultJdoDialect. |
|
||||||
* @param connectionFactory the connection factory of the JDO PersistenceManagerFactory, |
|
||||||
* which is used to initialize the default JDBC exception translator |
|
||||||
* @see javax.jdo.PersistenceManagerFactory#getConnectionFactory() |
|
||||||
* @see PersistenceManagerFactoryUtils#newJdbcExceptionTranslator(Object) |
|
||||||
*/ |
|
||||||
public DefaultJdoDialect(Object connectionFactory) { |
|
||||||
this.jdbcExceptionTranslator = PersistenceManagerFactoryUtils.newJdbcExceptionTranslator(connectionFactory); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Set the JDBC exception translator for this dialect. |
|
||||||
* <p>Applied to any SQLException root cause of a JDOException, if specified. |
|
||||||
* The default is to rely on the JDO provider's native exception translation. |
|
||||||
* @param jdbcExceptionTranslator exception translator |
|
||||||
* @see java.sql.SQLException |
|
||||||
* @see javax.jdo.JDOException#getCause() |
|
||||||
* @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator |
|
||||||
* @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator |
|
||||||
*/ |
|
||||||
public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) { |
|
||||||
this.jdbcExceptionTranslator = jdbcExceptionTranslator; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Return the JDBC exception translator for this dialect, if any. |
|
||||||
*/ |
|
||||||
public SQLExceptionTranslator getJdbcExceptionTranslator() { |
|
||||||
return this.jdbcExceptionTranslator; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
// Hooks for transaction management (used by JdoTransactionManager)
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** |
|
||||||
* This implementation invokes the standard JDO {@link Transaction#begin()} |
|
||||||
* method and also {@link Transaction#setIsolationLevel(String)} if necessary. |
|
||||||
* @see javax.jdo.Transaction#begin |
|
||||||
* @see org.springframework.transaction.InvalidIsolationLevelException |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public Object beginTransaction(Transaction transaction, TransactionDefinition definition) |
|
||||||
throws JDOException, SQLException, TransactionException { |
|
||||||
|
|
||||||
String jdoIsolationLevel = getJdoIsolationLevel(definition); |
|
||||||
if (jdoIsolationLevel != null) { |
|
||||||
transaction.setIsolationLevel(jdoIsolationLevel); |
|
||||||
} |
|
||||||
transaction.begin(); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Determine the JDO isolation level String to use for the given |
|
||||||
* Spring transaction definition. |
|
||||||
* @param definition the Spring transaction definition |
|
||||||
* @return the corresponding JDO isolation level String, or {@code null} |
|
||||||
* to indicate that no isolation level should be set explicitly |
|
||||||
* @see Transaction#setIsolationLevel(String) |
|
||||||
* @see Constants#TX_SERIALIZABLE |
|
||||||
* @see Constants#TX_REPEATABLE_READ |
|
||||||
* @see Constants#TX_READ_COMMITTED |
|
||||||
* @see Constants#TX_READ_UNCOMMITTED |
|
||||||
*/ |
|
||||||
protected String getJdoIsolationLevel(TransactionDefinition definition) { |
|
||||||
switch (definition.getIsolationLevel()) { |
|
||||||
case TransactionDefinition.ISOLATION_SERIALIZABLE: |
|
||||||
return Constants.TX_SERIALIZABLE; |
|
||||||
case TransactionDefinition.ISOLATION_REPEATABLE_READ: |
|
||||||
return Constants.TX_REPEATABLE_READ; |
|
||||||
case TransactionDefinition.ISOLATION_READ_COMMITTED: |
|
||||||
return Constants.TX_READ_COMMITTED; |
|
||||||
case TransactionDefinition.ISOLATION_READ_UNCOMMITTED: |
|
||||||
return Constants.TX_READ_UNCOMMITTED; |
|
||||||
default: |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* This implementation does nothing, as the default beginTransaction implementation |
|
||||||
* does not require any cleanup. |
|
||||||
* @see #beginTransaction |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public void cleanupTransaction(Object transactionData) { |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* This implementation returns a DataStoreConnectionHandle for JDO. |
|
||||||
* <p><b>NOTE:</b> A JDO DataStoreConnection is always a wrapper, |
|
||||||
* never the native JDBC Connection. If you need access to the native JDBC |
|
||||||
* Connection (or the connection pool handle, to be unwrapped via a Spring |
|
||||||
* NativeJdbcExtractor), override this method to return the native |
|
||||||
* Connection through the corresponding vendor-specific mechanism. |
|
||||||
* <p>A JDO DataStoreConnection is only "borrowed" from the PersistenceManager: |
|
||||||
* it needs to be returned as early as possible. Effectively, JDO requires the |
|
||||||
* fetched Connection to be closed before continuing PersistenceManager work. |
|
||||||
* For this reason, the exposed ConnectionHandle eagerly releases its JDBC |
|
||||||
* Connection at the end of each JDBC data access operation (that is, on |
|
||||||
* {@code DataSourceUtils.releaseConnection}). |
|
||||||
* @see javax.jdo.PersistenceManager#getDataStoreConnection() |
|
||||||
* @see org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor |
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public ConnectionHandle getJdbcConnection(PersistenceManager pm, boolean readOnly) |
|
||||||
throws JDOException, SQLException { |
|
||||||
|
|
||||||
return new DataStoreConnectionHandle(pm); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* This implementation does nothing, assuming that the Connection |
|
||||||
* will implicitly be closed with the PersistenceManager. |
|
||||||
* <p>If the JDO provider returns a Connection handle that it |
|
||||||
* expects the application to close, the dialect needs to invoke |
|
||||||
* {@code Connection.close} here. |
|
||||||
* @see java.sql.Connection#close() |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public void releaseJdbcConnection(ConnectionHandle conHandle, PersistenceManager pm) |
|
||||||
throws JDOException, SQLException { |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------------
|
|
||||||
// Hook for exception translation (used by JdoTransactionManager)
|
|
||||||
//-----------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** |
|
||||||
* Implementation of the PersistenceExceptionTranslator interface, |
|
||||||
* as autodetected by Spring's PersistenceExceptionTranslationPostProcessor. |
|
||||||
* <p>Converts the exception if it is a JDOException, using this JdoDialect. |
|
||||||
* Else returns {@code null} to indicate an unknown exception. |
|
||||||
* @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor |
|
||||||
* @see #translateException |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public DataAccessException translateExceptionIfPossible(RuntimeException ex) { |
|
||||||
if (ex instanceof JDOException) { |
|
||||||
return translateException((JDOException) ex); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* This implementation delegates to PersistenceManagerFactoryUtils. |
|
||||||
* @see PersistenceManagerFactoryUtils#convertJdoAccessException |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public DataAccessException translateException(JDOException ex) { |
|
||||||
if (getJdbcExceptionTranslator() != null && ex.getCause() instanceof SQLException) { |
|
||||||
return getJdbcExceptionTranslator().translate("JDO operation: " + ex.getMessage(), |
|
||||||
extractSqlStringFromException(ex), (SQLException) ex.getCause()); |
|
||||||
} |
|
||||||
return PersistenceManagerFactoryUtils.convertJdoAccessException(ex); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Template method for extracting a SQL String from the given exception. |
|
||||||
* <p>Default implementation always returns {@code null}. Can be overridden in |
|
||||||
* subclasses to extract SQL Strings for vendor-specific exception classes. |
|
||||||
* @param ex the JDOException, containing a SQLException |
|
||||||
* @return the SQL String, or {@code null} if none found |
|
||||||
*/ |
|
||||||
protected String extractSqlStringFromException(JDOException ex) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* ConnectionHandle implementation that fetches a new JDO DataStoreConnection |
|
||||||
* for every {@code getConnection} call and closes the Connection on |
|
||||||
* {@code releaseConnection}. This is necessary because JDO requires the |
|
||||||
* fetched Connection to be closed before continuing PersistenceManager work. |
|
||||||
* @see javax.jdo.PersistenceManager#getDataStoreConnection() |
|
||||||
*/ |
|
||||||
private static class DataStoreConnectionHandle implements ConnectionHandle { |
|
||||||
|
|
||||||
private final PersistenceManager persistenceManager; |
|
||||||
|
|
||||||
public DataStoreConnectionHandle(PersistenceManager persistenceManager) { |
|
||||||
this.persistenceManager = persistenceManager; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Connection getConnection() { |
|
||||||
return (Connection) this.persistenceManager.getDataStoreConnection(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void releaseConnection(Connection con) { |
|
||||||
JdbcUtils.closeConnection(con); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,169 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2013 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo; |
|
||||||
|
|
||||||
import java.sql.SQLException; |
|
||||||
import javax.jdo.JDOException; |
|
||||||
import javax.jdo.PersistenceManager; |
|
||||||
import javax.jdo.Transaction; |
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException; |
|
||||||
import org.springframework.jdbc.datasource.ConnectionHandle; |
|
||||||
import org.springframework.transaction.TransactionDefinition; |
|
||||||
import org.springframework.transaction.TransactionException; |
|
||||||
|
|
||||||
/** |
|
||||||
* SPI strategy that allows for customizing integration with a specific JDO provider, |
|
||||||
* in particular regarding transaction management and exception translation. To be |
|
||||||
* implemented for specific JDO providers such as JPOX, Kodo, Lido, Versant Open Access. |
|
||||||
* |
|
||||||
* <p>JDO 3.0 defines standard ways for most of the functionality covered here. |
|
||||||
* Hence, Spring's {@link DefaultJdoDialect} uses the corresponding JDO 3.0 methods |
|
||||||
* by default, to be overridden in a vendor-specific fashion if necessary. |
|
||||||
* Vendor-specific subclasses of {@link DefaultJdoDialect} are still required for special |
|
||||||
* transaction semantics and more sophisticated exception translation (if needed). |
|
||||||
* |
|
||||||
* <p>In general, it is recommended to derive from {@link DefaultJdoDialect} instead |
|
||||||
* of implementing this interface directly. This allows for inheriting common |
|
||||||
* behavior (present and future) from {@link DefaultJdoDialect}, only overriding |
|
||||||
* specific hooks to plug in concrete vendor-specific behavior. |
|
||||||
* |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @since 02.11.2003 |
|
||||||
* @see JdoTransactionManager#setJdoDialect |
|
||||||
* @see DefaultJdoDialect |
|
||||||
*/ |
|
||||||
public interface JdoDialect { |
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
// Hooks for transaction management (used by JdoTransactionManager)
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** |
|
||||||
* Begin the given JDO transaction, applying the semantics specified by the |
|
||||||
* given Spring transaction definition (in particular, an isolation level |
|
||||||
* and a timeout). Invoked by JdoTransactionManager on transaction begin. |
|
||||||
* <p>An implementation can configure the JDO Transaction object and then |
|
||||||
* invoke {@code begin}, or invoke a special begin method that takes, |
|
||||||
* for example, an isolation level. |
|
||||||
* <p>An implementation can also apply read-only flag and isolation level to the |
|
||||||
* underlying JDBC Connection before beginning the transaction. In that case, |
|
||||||
* a transaction data object can be returned that holds the previous isolation |
|
||||||
* level (and possibly other data), to be reset in {@code cleanupTransaction}. |
|
||||||
* <p>Implementations can also use the Spring transaction name, as exposed by the |
|
||||||
* passed-in TransactionDefinition, to optimize for specific data access use cases |
|
||||||
* (effectively using the current transaction name as use case identifier). |
|
||||||
* @param transaction the JDO transaction to begin |
|
||||||
* @param definition the Spring transaction definition that defines semantics |
|
||||||
* @return an arbitrary object that holds transaction data, if any |
|
||||||
* (to be passed into cleanupTransaction) |
|
||||||
* @throws JDOException if thrown by JDO methods |
|
||||||
* @throws SQLException if thrown by JDBC methods |
|
||||||
* @throws TransactionException in case of invalid arguments |
|
||||||
* @see #cleanupTransaction |
|
||||||
* @see javax.jdo.Transaction#begin |
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#prepareConnectionForTransaction |
|
||||||
*/ |
|
||||||
Object beginTransaction(Transaction transaction, TransactionDefinition definition) |
|
||||||
throws JDOException, SQLException, TransactionException; |
|
||||||
|
|
||||||
/** |
|
||||||
* Clean up the transaction via the given transaction data. |
|
||||||
* Invoked by JdoTransactionManager on transaction cleanup. |
|
||||||
* <p>An implementation can, for example, reset read-only flag and |
|
||||||
* isolation level of the underlying JDBC Connection. Furthermore, |
|
||||||
* an exposed data access use case can be reset here. |
|
||||||
* @param transactionData arbitrary object that holds transaction data, if any |
|
||||||
* (as returned by beginTransaction) |
|
||||||
* @see #beginTransaction |
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#resetConnectionAfterTransaction |
|
||||||
*/ |
|
||||||
void cleanupTransaction(Object transactionData); |
|
||||||
|
|
||||||
/** |
|
||||||
* Retrieve the JDBC Connection that the given JDO PersistenceManager uses underneath, |
|
||||||
* if accessing a relational database. This method will just get invoked if actually |
|
||||||
* needing access to the underlying JDBC Connection, usually within an active JDO |
|
||||||
* transaction (for example, by JdoTransactionManager). The returned handle will |
|
||||||
* be passed into the {@code releaseJdbcConnection} method when not needed anymore. |
|
||||||
* <p>Implementations are encouraged to return an unwrapped Connection object, i.e. |
|
||||||
* the Connection as they got it from the connection pool. This makes it easier for |
|
||||||
* application code to get at the underlying native JDBC Connection, like an |
|
||||||
* OracleConnection, which is sometimes necessary for LOB handling etc. We assume |
|
||||||
* that calling code knows how to properly handle the returned Connection object. |
|
||||||
* <p>In a simple case where the returned Connection will be auto-closed with the |
|
||||||
* PersistenceManager or can be released via the Connection object itself, an |
|
||||||
* implementation can return a SimpleConnectionHandle that just contains the |
|
||||||
* Connection. If some other object is needed in {@code releaseJdbcConnection}, |
|
||||||
* an implementation should use a special handle that references that other object. |
|
||||||
* @param pm the current JDO PersistenceManager |
|
||||||
* @param readOnly whether the Connection is only needed for read-only purposes |
|
||||||
* @return a handle for the JDBC Connection, to be passed into |
|
||||||
* {@code releaseJdbcConnection}, or {@code null} |
|
||||||
* if no JDBC Connection can be retrieved |
|
||||||
* @throws JDOException if thrown by JDO methods |
|
||||||
* @throws SQLException if thrown by JDBC methods |
|
||||||
* @see #releaseJdbcConnection |
|
||||||
* @see org.springframework.jdbc.datasource.ConnectionHandle#getConnection |
|
||||||
* @see org.springframework.jdbc.datasource.SimpleConnectionHandle |
|
||||||
* @see JdoTransactionManager#setDataSource |
|
||||||
* @see org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor |
|
||||||
*/ |
|
||||||
ConnectionHandle getJdbcConnection(PersistenceManager pm, boolean readOnly) |
|
||||||
throws JDOException, SQLException; |
|
||||||
|
|
||||||
/** |
|
||||||
* Release the given JDBC Connection, which has originally been retrieved |
|
||||||
* via {@code getJdbcConnection}. This should be invoked in any case, |
|
||||||
* to allow for proper release of the retrieved Connection handle. |
|
||||||
* <p>An implementation might simply do nothing, if the Connection returned |
|
||||||
* by {@code getJdbcConnection} will be implicitly closed when the JDO |
|
||||||
* transaction completes or when the PersistenceManager is closed. |
|
||||||
* @param conHandle the JDBC Connection handle to release |
|
||||||
* @param pm the current JDO PersistenceManager |
|
||||||
* @throws JDOException if thrown by JDO methods |
|
||||||
* @throws SQLException if thrown by JDBC methods |
|
||||||
* @see #getJdbcConnection |
|
||||||
*/ |
|
||||||
void releaseJdbcConnection(ConnectionHandle conHandle, PersistenceManager pm) |
|
||||||
throws JDOException, SQLException; |
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------------
|
|
||||||
// Hook for exception translation (used by JdoTransactionManager)
|
|
||||||
//-----------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** |
|
||||||
* Translate the given JDOException to a corresponding exception from Spring's |
|
||||||
* generic DataAccessException hierarchy. An implementation should apply |
|
||||||
* PersistenceManagerFactoryUtils' standard exception translation if can't do |
|
||||||
* anything more specific. |
|
||||||
* <p>Of particular importance is the correct translation to |
|
||||||
* DataIntegrityViolationException, for example on constraint violation. |
|
||||||
* Unfortunately, standard JDO does not allow for portable detection of this. |
|
||||||
* <p>Can use a SQLExceptionTranslator for translating underlying SQLExceptions |
|
||||||
* in a database-specific fashion. |
|
||||||
* @param ex the JDOException thrown |
|
||||||
* @return the corresponding DataAccessException (must not be {@code null}) |
|
||||||
* @see JdoTransactionManager#convertJdoAccessException |
|
||||||
* @see PersistenceManagerFactoryUtils#convertJdoAccessException |
|
||||||
* @see org.springframework.dao.DataIntegrityViolationException |
|
||||||
* @see org.springframework.jdbc.support.SQLExceptionTranslator |
|
||||||
*/ |
|
||||||
DataAccessException translateException(JDOException ex); |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,42 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2012 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo; |
|
||||||
|
|
||||||
import javax.jdo.JDOHelper; |
|
||||||
import javax.jdo.JDOObjectNotFoundException; |
|
||||||
|
|
||||||
import org.springframework.orm.ObjectRetrievalFailureException; |
|
||||||
|
|
||||||
/** |
|
||||||
* JDO-specific subclass of ObjectRetrievalFailureException. |
|
||||||
* Converts JDO's JDOObjectNotFoundException. |
|
||||||
* |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @since 1.1 |
|
||||||
* @see PersistenceManagerFactoryUtils#convertJdoAccessException |
|
||||||
*/ |
|
||||||
@SuppressWarnings("serial") |
|
||||||
public class JdoObjectRetrievalFailureException extends ObjectRetrievalFailureException { |
|
||||||
|
|
||||||
public JdoObjectRetrievalFailureException(JDOObjectNotFoundException ex) { |
|
||||||
// Extract information about the failed object from the JDOException, if available.
|
|
||||||
super((ex.getFailedObject() != null ? ex.getFailedObject().getClass() : null), |
|
||||||
(ex.getFailedObject() != null ? JDOHelper.getObjectId(ex.getFailedObject()) : null), |
|
||||||
ex.getMessage(), ex); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,42 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2012 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo; |
|
||||||
|
|
||||||
import javax.jdo.JDOHelper; |
|
||||||
import javax.jdo.JDOOptimisticVerificationException; |
|
||||||
|
|
||||||
import org.springframework.orm.ObjectOptimisticLockingFailureException; |
|
||||||
|
|
||||||
/** |
|
||||||
* JDO-specific subclass of ObjectOptimisticLockingFailureException. |
|
||||||
* Converts JDO's JDOOptimisticVerificationException. |
|
||||||
* |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @since 1.1 |
|
||||||
* @see PersistenceManagerFactoryUtils#convertJdoAccessException |
|
||||||
*/ |
|
||||||
@SuppressWarnings("serial") |
|
||||||
public class JdoOptimisticLockingFailureException extends ObjectOptimisticLockingFailureException { |
|
||||||
|
|
||||||
public JdoOptimisticLockingFailureException(JDOOptimisticVerificationException ex) { |
|
||||||
// Extract information about the failed object from the JDOException, if available.
|
|
||||||
super((ex.getFailedObject() != null ? ex.getFailedObject().getClass() : null), |
|
||||||
(ex.getFailedObject() != null ? JDOHelper.getObjectId(ex.getFailedObject()) : null), |
|
||||||
ex.getMessage(), ex); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,43 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2012 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo; |
|
||||||
|
|
||||||
import javax.jdo.JDODataStoreException; |
|
||||||
import javax.jdo.JDOFatalDataStoreException; |
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessResourceFailureException; |
|
||||||
|
|
||||||
/** |
|
||||||
* JDO-specific subclass of DataAccessResourceFailureException. |
|
||||||
* Converts JDO's JDODataStoreException and JDOFatalDataStoreException. |
|
||||||
* |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @since 1.1 |
|
||||||
* @see PersistenceManagerFactoryUtils#convertJdoAccessException |
|
||||||
*/ |
|
||||||
@SuppressWarnings("serial") |
|
||||||
public class JdoResourceFailureException extends DataAccessResourceFailureException { |
|
||||||
|
|
||||||
public JdoResourceFailureException(JDODataStoreException ex) { |
|
||||||
super(ex.getMessage(), ex); |
|
||||||
} |
|
||||||
|
|
||||||
public JdoResourceFailureException(JDOFatalDataStoreException ex) { |
|
||||||
super(ex.getMessage(), ex); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,39 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2012 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo; |
|
||||||
|
|
||||||
import javax.jdo.JDOException; |
|
||||||
|
|
||||||
import org.springframework.dao.UncategorizedDataAccessException; |
|
||||||
|
|
||||||
/** |
|
||||||
* JDO-specific subclass of UncategorizedDataAccessException, |
|
||||||
* for JDO system errors that do not match any concrete |
|
||||||
* {@code org.springframework.dao} exceptions. |
|
||||||
* |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @since 03.06.2003 |
|
||||||
* @see PersistenceManagerFactoryUtils#convertJdoAccessException |
|
||||||
*/ |
|
||||||
@SuppressWarnings("serial") |
|
||||||
public class JdoSystemException extends UncategorizedDataAccessException { |
|
||||||
|
|
||||||
public JdoSystemException(JDOException ex) { |
|
||||||
super(ex.getMessage(), ex); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,619 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2014 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo; |
|
||||||
|
|
||||||
import javax.jdo.JDOException; |
|
||||||
import javax.jdo.PersistenceManager; |
|
||||||
import javax.jdo.PersistenceManagerFactory; |
|
||||||
import javax.jdo.Transaction; |
|
||||||
import javax.sql.DataSource; |
|
||||||
|
|
||||||
import org.springframework.beans.factory.InitializingBean; |
|
||||||
import org.springframework.dao.DataAccessException; |
|
||||||
import org.springframework.jdbc.datasource.ConnectionHandle; |
|
||||||
import org.springframework.jdbc.datasource.ConnectionHolder; |
|
||||||
import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport; |
|
||||||
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy; |
|
||||||
import org.springframework.transaction.CannotCreateTransactionException; |
|
||||||
import org.springframework.transaction.IllegalTransactionStateException; |
|
||||||
import org.springframework.transaction.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.DelegatingTransactionDefinition; |
|
||||||
import org.springframework.transaction.support.ResourceTransactionManager; |
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager; |
|
||||||
|
|
||||||
/** |
|
||||||
* {@link org.springframework.transaction.PlatformTransactionManager} implementation for a |
|
||||||
* single JDO {@link javax.jdo.PersistenceManagerFactory}. Binds a JDO PersistenceManager |
|
||||||
* from the specified factory to the thread, potentially allowing for one thread-bound |
|
||||||
* PersistenceManager per factory. {@link PersistenceManagerFactoryUtils} and |
|
||||||
* {@link org.springframework.orm.jdo.support.SpringPersistenceManagerProxyBean} are aware |
|
||||||
* of thread-bound persistence managers and participate in such transactions automatically. |
|
||||||
* Using either of those (or going through a {@link TransactionAwarePersistenceManagerFactoryProxy} |
|
||||||
* is required for JDO access code supporting this transaction management mechanism. |
|
||||||
* |
|
||||||
* <p>This transaction manager is appropriate for applications that use a single |
|
||||||
* JDO PersistenceManagerFactory for transactional data access. JTA (usually through |
|
||||||
* {@link org.springframework.transaction.jta.JtaTransactionManager}) is necessary |
|
||||||
* for accessing multiple transactional resources within the same transaction. |
|
||||||
* Note that you need to configure your JDO provider accordingly in order to make |
|
||||||
* it participate in JTA transactions. |
|
||||||
* |
|
||||||
* <p>This transaction manager also supports direct DataSource access within a |
|
||||||
* transaction (i.e. plain JDBC code working with the same DataSource). |
|
||||||
* This allows for mixing services which access JDO and services which use plain |
|
||||||
* JDBC (without being aware of JDO)! Application code needs to stick to the |
|
||||||
* same simple Connection lookup pattern as with |
|
||||||
* {@link org.springframework.jdbc.datasource.DataSourceTransactionManager} |
|
||||||
* (i.e. {@link org.springframework.jdbc.datasource.DataSourceUtils#getConnection} |
|
||||||
* or going through a |
|
||||||
* {@link org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy}). |
|
||||||
* |
|
||||||
* <p>Note: To be able to register a DataSource's Connection for plain JDBC code, |
|
||||||
* this instance needs to be aware of the DataSource ({@link #setDataSource}). |
|
||||||
* The given DataSource should obviously match the one used by the given |
|
||||||
* PersistenceManagerFactory. This transaction manager will autodetect the DataSource |
|
||||||
* that acts as "connectionFactory" of the PersistenceManagerFactory, so you usually |
|
||||||
* don't need to explicitly specify the "dataSource" property. |
|
||||||
* |
|
||||||
* <p>This transaction manager supports nested transactions via JDBC 3.0 Savepoints. |
|
||||||
* The {@link #setNestedTransactionAllowed} "nestedTransactionAllowed"} flag defaults |
|
||||||
* to "false", though, as nested transactions will just apply to the JDBC Connection, |
|
||||||
* not to the JDO PersistenceManager and its cached entity objects and related context. |
|
||||||
* You can manually set the flag to "true" if you want to use nested transactions |
|
||||||
* for JDBC access code which participates in JDO transactions (provided that your |
|
||||||
* JDBC driver supports Savepoints). <i>Note that JDO itself does not support |
|
||||||
* nested transactions! Hence, do not expect JDO access code to semantically |
|
||||||
* participate in a nested transaction.</i> |
|
||||||
* |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @since 03.06.2003 |
|
||||||
* @see #setPersistenceManagerFactory |
|
||||||
* @see #setDataSource |
|
||||||
* @see javax.jdo.PersistenceManagerFactory#getConnectionFactory |
|
||||||
* @see LocalPersistenceManagerFactoryBean |
|
||||||
* @see PersistenceManagerFactoryUtils#getPersistenceManager |
|
||||||
* @see PersistenceManagerFactoryUtils#releasePersistenceManager |
|
||||||
* @see TransactionAwarePersistenceManagerFactoryProxy |
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection |
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection |
|
||||||
* @see org.springframework.jdbc.core.JdbcTemplate |
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager |
|
||||||
* @see org.springframework.transaction.jta.JtaTransactionManager |
|
||||||
*/ |
|
||||||
@SuppressWarnings("serial") |
|
||||||
public class JdoTransactionManager extends AbstractPlatformTransactionManager |
|
||||||
implements ResourceTransactionManager, InitializingBean { |
|
||||||
|
|
||||||
private PersistenceManagerFactory persistenceManagerFactory; |
|
||||||
|
|
||||||
private DataSource dataSource; |
|
||||||
|
|
||||||
private boolean autodetectDataSource = true; |
|
||||||
|
|
||||||
private JdoDialect jdoDialect; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Create a new JdoTransactionManager instance. |
|
||||||
* A PersistenceManagerFactory has to be set to be able to use it. |
|
||||||
* @see #setPersistenceManagerFactory |
|
||||||
*/ |
|
||||||
public JdoTransactionManager() { |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Create a new JdoTransactionManager instance. |
|
||||||
* @param pmf PersistenceManagerFactory to manage transactions for |
|
||||||
*/ |
|
||||||
public JdoTransactionManager(PersistenceManagerFactory pmf) { |
|
||||||
this.persistenceManagerFactory = pmf; |
|
||||||
afterPropertiesSet(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Set the PersistenceManagerFactory that this instance should manage transactions for. |
|
||||||
* <p>The PersistenceManagerFactory specified here should be the target |
|
||||||
* PersistenceManagerFactory to manage transactions for, not a |
|
||||||
* TransactionAwarePersistenceManagerFactoryProxy. Only data access |
|
||||||
* code may work with TransactionAwarePersistenceManagerFactoryProxy, while the |
|
||||||
* transaction manager needs to work on the underlying target PersistenceManagerFactory. |
|
||||||
* @see TransactionAwarePersistenceManagerFactoryProxy |
|
||||||
*/ |
|
||||||
public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) { |
|
||||||
this.persistenceManagerFactory = pmf; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Return the PersistenceManagerFactory that this instance should manage transactions for. |
|
||||||
*/ |
|
||||||
public PersistenceManagerFactory getPersistenceManagerFactory() { |
|
||||||
return this.persistenceManagerFactory; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Set the JDBC DataSource that this instance should manage transactions for. |
|
||||||
* The DataSource should match the one used by the JDO PersistenceManagerFactory: |
|
||||||
* for example, you could specify the same JNDI DataSource for both. |
|
||||||
* <p>If the PersistenceManagerFactory uses a DataSource as connection factory, |
|
||||||
* the DataSource will be autodetected: You can still explicitly specify the |
|
||||||
* DataSource, but you don't need to in this case. |
|
||||||
* <p>A transactional JDBC Connection for this DataSource will be provided to |
|
||||||
* application code accessing this DataSource directly via DataSourceUtils |
|
||||||
* or JdbcTemplate. The Connection will be taken from the JDO PersistenceManager. |
|
||||||
* <p>Note that you need to use a JDO dialect for a specific JDO provider to |
|
||||||
* allow for exposing JDO transactions as JDBC transactions. |
|
||||||
* <p>The DataSource specified here should be the target DataSource to manage |
|
||||||
* transactions for, not a TransactionAwareDataSourceProxy. Only data access |
|
||||||
* code may work with TransactionAwareDataSourceProxy, while the transaction |
|
||||||
* manager needs to work on the underlying target DataSource. If there's |
|
||||||
* nevertheless a TransactionAwareDataSourceProxy passed in, it will be |
|
||||||
* unwrapped to extract its target DataSource. |
|
||||||
* @see #setAutodetectDataSource |
|
||||||
* @see #setJdoDialect |
|
||||||
* @see javax.jdo.PersistenceManagerFactory#getConnectionFactory |
|
||||||
* @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy |
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceUtils |
|
||||||
* @see org.springframework.jdbc.core.JdbcTemplate |
|
||||||
*/ |
|
||||||
public void setDataSource(DataSource dataSource) { |
|
||||||
if (dataSource instanceof TransactionAwareDataSourceProxy) { |
|
||||||
// If we got a TransactionAwareDataSourceProxy, we need to perform transactions
|
|
||||||
// for its underlying target DataSource, else data access code won't see
|
|
||||||
// properly exposed transactions (i.e. transactions for the target DataSource).
|
|
||||||
this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource(); |
|
||||||
} |
|
||||||
else { |
|
||||||
this.dataSource = dataSource; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Return the JDBC DataSource that this instance manages transactions for. |
|
||||||
*/ |
|
||||||
public DataSource getDataSource() { |
|
||||||
return this.dataSource; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Set whether to autodetect a JDBC DataSource used by the JDO PersistenceManagerFactory, |
|
||||||
* as returned by the {@code getConnectionFactory()} method. Default is "true". |
|
||||||
* <p>Can be turned off to deliberately ignore an available DataSource, |
|
||||||
* to not expose JDO transactions as JDBC transactions for that DataSource. |
|
||||||
* @see #setDataSource |
|
||||||
* @see javax.jdo.PersistenceManagerFactory#getConnectionFactory |
|
||||||
*/ |
|
||||||
public void setAutodetectDataSource(boolean autodetectDataSource) { |
|
||||||
this.autodetectDataSource = autodetectDataSource; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Set the JDO dialect to use for this transaction manager. |
|
||||||
* <p>The dialect object can be used to retrieve the underlying JDBC connection |
|
||||||
* and thus allows for exposing JDO transactions as JDBC transactions. |
|
||||||
* @see JdoDialect#getJdbcConnection |
|
||||||
*/ |
|
||||||
public void setJdoDialect(JdoDialect jdoDialect) { |
|
||||||
this.jdoDialect = jdoDialect; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Return the JDO dialect to use for this transaction manager. |
|
||||||
* <p>Creates a default one for the specified PersistenceManagerFactory if none set. |
|
||||||
*/ |
|
||||||
public JdoDialect getJdoDialect() { |
|
||||||
if (this.jdoDialect == null) { |
|
||||||
this.jdoDialect = new DefaultJdoDialect(); |
|
||||||
} |
|
||||||
return this.jdoDialect; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Eagerly initialize the JDO dialect, creating a default one |
|
||||||
* for the specified PersistenceManagerFactory if none set. |
|
||||||
* Auto-detect the PersistenceManagerFactory's DataSource, if any. |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public void afterPropertiesSet() { |
|
||||||
if (getPersistenceManagerFactory() == null) { |
|
||||||
throw new IllegalArgumentException("Property 'persistenceManagerFactory' is required"); |
|
||||||
} |
|
||||||
// Build default JdoDialect if none explicitly specified.
|
|
||||||
if (this.jdoDialect == null) { |
|
||||||
this.jdoDialect = new DefaultJdoDialect(getPersistenceManagerFactory().getConnectionFactory()); |
|
||||||
} |
|
||||||
|
|
||||||
// Check for DataSource as connection factory.
|
|
||||||
if (this.autodetectDataSource && getDataSource() == null) { |
|
||||||
Object pmfcf = getPersistenceManagerFactory().getConnectionFactory(); |
|
||||||
if (pmfcf instanceof DataSource) { |
|
||||||
// Use the PersistenceManagerFactory's DataSource for exposing transactions to JDBC code.
|
|
||||||
this.dataSource = (DataSource) pmfcf; |
|
||||||
if (logger.isInfoEnabled()) { |
|
||||||
logger.info("Using DataSource [" + this.dataSource + |
|
||||||
"] of JDO PersistenceManagerFactory for JdoTransactionManager"); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public Object getResourceFactory() { |
|
||||||
return getPersistenceManagerFactory(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected Object doGetTransaction() { |
|
||||||
JdoTransactionObject txObject = new JdoTransactionObject(); |
|
||||||
txObject.setSavepointAllowed(isNestedTransactionAllowed()); |
|
||||||
|
|
||||||
PersistenceManagerHolder pmHolder = (PersistenceManagerHolder) |
|
||||||
TransactionSynchronizationManager.getResource(getPersistenceManagerFactory()); |
|
||||||
if (pmHolder != null) { |
|
||||||
if (logger.isDebugEnabled()) { |
|
||||||
logger.debug("Found thread-bound PersistenceManager [" + |
|
||||||
pmHolder.getPersistenceManager() + "] for JDO transaction"); |
|
||||||
} |
|
||||||
txObject.setPersistenceManagerHolder(pmHolder, false); |
|
||||||
} |
|
||||||
|
|
||||||
if (getDataSource() != null) { |
|
||||||
ConnectionHolder conHolder = (ConnectionHolder) |
|
||||||
TransactionSynchronizationManager.getResource(getDataSource()); |
|
||||||
txObject.setConnectionHolder(conHolder); |
|
||||||
} |
|
||||||
|
|
||||||
return txObject; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected boolean isExistingTransaction(Object transaction) { |
|
||||||
return ((JdoTransactionObject) transaction).hasTransaction(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected void doBegin(Object transaction, TransactionDefinition definition) { |
|
||||||
JdoTransactionObject txObject = (JdoTransactionObject) transaction; |
|
||||||
|
|
||||||
if (txObject.hasConnectionHolder() && !txObject.getConnectionHolder().isSynchronizedWithTransaction()) { |
|
||||||
throw new IllegalTransactionStateException( |
|
||||||
"Pre-bound JDBC Connection found! JdoTransactionManager does not support " + |
|
||||||
"running within DataSourceTransactionManager if told to manage the DataSource itself. " + |
|
||||||
"It is recommended to use a single JdoTransactionManager for all transactions " + |
|
||||||
"on a single DataSource, no matter whether JDO or JDBC access."); |
|
||||||
} |
|
||||||
|
|
||||||
PersistenceManager pm; |
|
||||||
|
|
||||||
try { |
|
||||||
if (txObject.getPersistenceManagerHolder() == null || |
|
||||||
txObject.getPersistenceManagerHolder().isSynchronizedWithTransaction()) { |
|
||||||
PersistenceManager newPm = getPersistenceManagerFactory().getPersistenceManager(); |
|
||||||
if (logger.isDebugEnabled()) { |
|
||||||
logger.debug("Opened new PersistenceManager [" + newPm + "] for JDO transaction"); |
|
||||||
} |
|
||||||
txObject.setPersistenceManagerHolder(new PersistenceManagerHolder(newPm), true); |
|
||||||
} |
|
||||||
|
|
||||||
pm = txObject.getPersistenceManagerHolder().getPersistenceManager(); |
|
||||||
|
|
||||||
// Delegate to JdoDialect for actual transaction begin.
|
|
||||||
final int timeoutToUse = determineTimeout(definition); |
|
||||||
Object transactionData = getJdoDialect().beginTransaction(pm.currentTransaction(), |
|
||||||
new DelegatingTransactionDefinition(definition) { |
|
||||||
@Override |
|
||||||
public int getTimeout() { |
|
||||||
return timeoutToUse; |
|
||||||
} |
|
||||||
}); |
|
||||||
txObject.setTransactionData(transactionData); |
|
||||||
|
|
||||||
// Register transaction timeout.
|
|
||||||
if (timeoutToUse != TransactionDefinition.TIMEOUT_DEFAULT) { |
|
||||||
txObject.getPersistenceManagerHolder().setTimeoutInSeconds(timeoutToUse); |
|
||||||
} |
|
||||||
|
|
||||||
// Register the JDO PersistenceManager's JDBC Connection for the DataSource, if set.
|
|
||||||
if (getDataSource() != null) { |
|
||||||
ConnectionHandle conHandle = getJdoDialect().getJdbcConnection(pm, definition.isReadOnly()); |
|
||||||
if (conHandle != null) { |
|
||||||
ConnectionHolder conHolder = new ConnectionHolder(conHandle); |
|
||||||
if (timeoutToUse != TransactionDefinition.TIMEOUT_DEFAULT) { |
|
||||||
conHolder.setTimeoutInSeconds(timeoutToUse); |
|
||||||
} |
|
||||||
if (logger.isDebugEnabled()) { |
|
||||||
logger.debug("Exposing JDO transaction as JDBC transaction [" + |
|
||||||
conHolder.getConnectionHandle() + "]"); |
|
||||||
} |
|
||||||
TransactionSynchronizationManager.bindResource(getDataSource(), conHolder); |
|
||||||
txObject.setConnectionHolder(conHolder); |
|
||||||
} |
|
||||||
else { |
|
||||||
if (logger.isDebugEnabled()) { |
|
||||||
logger.debug("Not exposing JDO transaction [" + pm + "] as JDBC transaction because " + |
|
||||||
"JdoDialect [" + getJdoDialect() + "] does not support JDBC Connection retrieval"); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Bind the persistence manager holder to the thread.
|
|
||||||
if (txObject.isNewPersistenceManagerHolder()) { |
|
||||||
TransactionSynchronizationManager.bindResource( |
|
||||||
getPersistenceManagerFactory(), txObject.getPersistenceManagerHolder()); |
|
||||||
} |
|
||||||
txObject.getPersistenceManagerHolder().setSynchronizedWithTransaction(true); |
|
||||||
} |
|
||||||
|
|
||||||
catch (TransactionException ex) { |
|
||||||
closePersistenceManagerAfterFailedBegin(txObject); |
|
||||||
throw ex; |
|
||||||
} |
|
||||||
catch (Throwable ex) { |
|
||||||
closePersistenceManagerAfterFailedBegin(txObject); |
|
||||||
throw new CannotCreateTransactionException("Could not open JDO PersistenceManager for transaction", ex); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Close the current transaction's EntityManager. |
|
||||||
* Called after a transaction begin attempt failed. |
|
||||||
* @param txObject the current transaction |
|
||||||
*/ |
|
||||||
protected void closePersistenceManagerAfterFailedBegin(JdoTransactionObject txObject) { |
|
||||||
if (txObject.isNewPersistenceManagerHolder()) { |
|
||||||
PersistenceManager pm = txObject.getPersistenceManagerHolder().getPersistenceManager(); |
|
||||||
try { |
|
||||||
if (pm.currentTransaction().isActive()) { |
|
||||||
pm.currentTransaction().rollback(); |
|
||||||
} |
|
||||||
} |
|
||||||
catch (Throwable ex) { |
|
||||||
logger.debug("Could not rollback PersistenceManager after failed transaction begin", ex); |
|
||||||
} |
|
||||||
finally { |
|
||||||
PersistenceManagerFactoryUtils.releasePersistenceManager(pm, getPersistenceManagerFactory()); |
|
||||||
} |
|
||||||
txObject.setPersistenceManagerHolder(null, false); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected Object doSuspend(Object transaction) { |
|
||||||
JdoTransactionObject txObject = (JdoTransactionObject) transaction; |
|
||||||
txObject.setPersistenceManagerHolder(null, false); |
|
||||||
PersistenceManagerHolder persistenceManagerHolder = (PersistenceManagerHolder) |
|
||||||
TransactionSynchronizationManager.unbindResource(getPersistenceManagerFactory()); |
|
||||||
txObject.setConnectionHolder(null); |
|
||||||
ConnectionHolder connectionHolder = null; |
|
||||||
if (getDataSource() != null && TransactionSynchronizationManager.hasResource(getDataSource())) { |
|
||||||
connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.unbindResource(getDataSource()); |
|
||||||
} |
|
||||||
return new SuspendedResourcesHolder(persistenceManagerHolder, connectionHolder); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected void doResume(Object transaction, Object suspendedResources) { |
|
||||||
SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources; |
|
||||||
TransactionSynchronizationManager.bindResource( |
|
||||||
getPersistenceManagerFactory(), resourcesHolder.getPersistenceManagerHolder()); |
|
||||||
if (getDataSource() != null && resourcesHolder.getConnectionHolder() != null) { |
|
||||||
TransactionSynchronizationManager.bindResource(getDataSource(), resourcesHolder.getConnectionHolder()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* This implementation returns "true": a JDO commit will properly handle |
|
||||||
* transactions that have been marked rollback-only at a global level. |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
protected boolean shouldCommitOnGlobalRollbackOnly() { |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected void doCommit(DefaultTransactionStatus status) { |
|
||||||
JdoTransactionObject txObject = (JdoTransactionObject) status.getTransaction(); |
|
||||||
if (status.isDebug()) { |
|
||||||
logger.debug("Committing JDO transaction on PersistenceManager [" + |
|
||||||
txObject.getPersistenceManagerHolder().getPersistenceManager() + "]"); |
|
||||||
} |
|
||||||
try { |
|
||||||
Transaction tx = txObject.getPersistenceManagerHolder().getPersistenceManager().currentTransaction(); |
|
||||||
tx.commit(); |
|
||||||
} |
|
||||||
catch (JDOException ex) { |
|
||||||
// Assumably failed to flush changes to database.
|
|
||||||
throw convertJdoAccessException(ex); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected void doRollback(DefaultTransactionStatus status) { |
|
||||||
JdoTransactionObject txObject = (JdoTransactionObject) status.getTransaction(); |
|
||||||
if (status.isDebug()) { |
|
||||||
logger.debug("Rolling back JDO transaction on PersistenceManager [" + |
|
||||||
txObject.getPersistenceManagerHolder().getPersistenceManager() + "]"); |
|
||||||
} |
|
||||||
try { |
|
||||||
Transaction tx = txObject.getPersistenceManagerHolder().getPersistenceManager().currentTransaction(); |
|
||||||
if (tx.isActive()) { |
|
||||||
tx.rollback(); |
|
||||||
} |
|
||||||
} |
|
||||||
catch (JDOException ex) { |
|
||||||
throw new TransactionSystemException("Could not roll back JDO transaction", ex); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected void doSetRollbackOnly(DefaultTransactionStatus status) { |
|
||||||
JdoTransactionObject txObject = (JdoTransactionObject) status.getTransaction(); |
|
||||||
if (status.isDebug()) { |
|
||||||
logger.debug("Setting JDO transaction on PersistenceManager [" + |
|
||||||
txObject.getPersistenceManagerHolder().getPersistenceManager() + "] rollback-only"); |
|
||||||
} |
|
||||||
txObject.setRollbackOnly(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected void doCleanupAfterCompletion(Object transaction) { |
|
||||||
JdoTransactionObject txObject = (JdoTransactionObject) transaction; |
|
||||||
|
|
||||||
// Remove the persistence manager holder from the thread.
|
|
||||||
if (txObject.isNewPersistenceManagerHolder()) { |
|
||||||
TransactionSynchronizationManager.unbindResource(getPersistenceManagerFactory()); |
|
||||||
} |
|
||||||
txObject.getPersistenceManagerHolder().clear(); |
|
||||||
|
|
||||||
// Remove the JDBC connection holder from the thread, if exposed.
|
|
||||||
if (txObject.hasConnectionHolder()) { |
|
||||||
TransactionSynchronizationManager.unbindResource(getDataSource()); |
|
||||||
try { |
|
||||||
getJdoDialect().releaseJdbcConnection(txObject.getConnectionHolder().getConnectionHandle(), |
|
||||||
txObject.getPersistenceManagerHolder().getPersistenceManager()); |
|
||||||
} |
|
||||||
catch (Throwable ex) { |
|
||||||
// Just log it, to keep a transaction-related exception.
|
|
||||||
logger.debug("Could not release JDBC connection after transaction", ex); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
getJdoDialect().cleanupTransaction(txObject.getTransactionData()); |
|
||||||
|
|
||||||
if (txObject.isNewPersistenceManagerHolder()) { |
|
||||||
PersistenceManager pm = txObject.getPersistenceManagerHolder().getPersistenceManager(); |
|
||||||
if (logger.isDebugEnabled()) { |
|
||||||
logger.debug("Closing JDO PersistenceManager [" + pm + "] after transaction"); |
|
||||||
} |
|
||||||
PersistenceManagerFactoryUtils.releasePersistenceManager(pm, getPersistenceManagerFactory()); |
|
||||||
} |
|
||||||
else { |
|
||||||
logger.debug("Not closing pre-bound JDO PersistenceManager after transaction"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Convert the given JDOException to an appropriate exception from the |
|
||||||
* {@code org.springframework.dao} hierarchy. |
|
||||||
* <p>The default implementation delegates to the JdoDialect. |
|
||||||
* May be overridden in subclasses. |
|
||||||
* @param ex JDOException that occured |
|
||||||
* @return the corresponding DataAccessException instance |
|
||||||
* @see JdoDialect#translateException |
|
||||||
*/ |
|
||||||
protected DataAccessException convertJdoAccessException(JDOException ex) { |
|
||||||
return getJdoDialect().translateException(ex); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* JDO transaction object, representing a PersistenceManagerHolder. |
|
||||||
* Used as transaction object by JdoTransactionManager. |
|
||||||
*/ |
|
||||||
private class JdoTransactionObject extends JdbcTransactionObjectSupport { |
|
||||||
|
|
||||||
private PersistenceManagerHolder persistenceManagerHolder; |
|
||||||
|
|
||||||
private boolean newPersistenceManagerHolder; |
|
||||||
|
|
||||||
private Object transactionData; |
|
||||||
|
|
||||||
public void setPersistenceManagerHolder( |
|
||||||
PersistenceManagerHolder persistenceManagerHolder, boolean newPersistenceManagerHolder) { |
|
||||||
this.persistenceManagerHolder = persistenceManagerHolder; |
|
||||||
this.newPersistenceManagerHolder = newPersistenceManagerHolder; |
|
||||||
} |
|
||||||
|
|
||||||
public PersistenceManagerHolder getPersistenceManagerHolder() { |
|
||||||
return this.persistenceManagerHolder; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isNewPersistenceManagerHolder() { |
|
||||||
return this.newPersistenceManagerHolder; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean hasTransaction() { |
|
||||||
return (this.persistenceManagerHolder != null && this.persistenceManagerHolder.isTransactionActive()); |
|
||||||
} |
|
||||||
|
|
||||||
public void setTransactionData(Object transactionData) { |
|
||||||
this.transactionData = transactionData; |
|
||||||
this.persistenceManagerHolder.setTransactionActive(true); |
|
||||||
} |
|
||||||
|
|
||||||
public Object getTransactionData() { |
|
||||||
return this.transactionData; |
|
||||||
} |
|
||||||
|
|
||||||
public void setRollbackOnly() { |
|
||||||
Transaction tx = this.persistenceManagerHolder.getPersistenceManager().currentTransaction(); |
|
||||||
if (tx.isActive()) { |
|
||||||
tx.setRollbackOnly(); |
|
||||||
} |
|
||||||
if (hasConnectionHolder()) { |
|
||||||
getConnectionHolder().setRollbackOnly(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isRollbackOnly() { |
|
||||||
Transaction tx = this.persistenceManagerHolder.getPersistenceManager().currentTransaction(); |
|
||||||
return tx.getRollbackOnly(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void flush() { |
|
||||||
try { |
|
||||||
this.persistenceManagerHolder.getPersistenceManager().flush(); |
|
||||||
} |
|
||||||
catch (JDOException ex) { |
|
||||||
throw convertJdoAccessException(ex); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Holder for suspended resources. |
|
||||||
* Used internally by {@code doSuspend} and {@code doResume}. |
|
||||||
*/ |
|
||||||
private static class SuspendedResourcesHolder { |
|
||||||
|
|
||||||
private final PersistenceManagerHolder persistenceManagerHolder; |
|
||||||
|
|
||||||
private final ConnectionHolder connectionHolder; |
|
||||||
|
|
||||||
private SuspendedResourcesHolder(PersistenceManagerHolder pmHolder, ConnectionHolder conHolder) { |
|
||||||
this.persistenceManagerHolder = pmHolder; |
|
||||||
this.connectionHolder = conHolder; |
|
||||||
} |
|
||||||
|
|
||||||
private PersistenceManagerHolder getPersistenceManagerHolder() { |
|
||||||
return this.persistenceManagerHolder; |
|
||||||
} |
|
||||||
|
|
||||||
private ConnectionHolder getConnectionHolder() { |
|
||||||
return this.connectionHolder; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,43 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2012 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo; |
|
||||||
|
|
||||||
import javax.jdo.JDOFatalUserException; |
|
||||||
import javax.jdo.JDOUserException; |
|
||||||
|
|
||||||
import org.springframework.dao.InvalidDataAccessApiUsageException; |
|
||||||
|
|
||||||
/** |
|
||||||
* JDO-specific subclass of InvalidDataAccessApiUsageException. |
|
||||||
* Converts JDO's JDOUserException and JDOFatalUserException. |
|
||||||
* |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @since 03.06.2003 |
|
||||||
* @see PersistenceManagerFactoryUtils#convertJdoAccessException |
|
||||||
*/ |
|
||||||
@SuppressWarnings("serial") |
|
||||||
public class JdoUsageException extends InvalidDataAccessApiUsageException { |
|
||||||
|
|
||||||
public JdoUsageException(JDOUserException ex) { |
|
||||||
super(ex.getMessage(), ex); |
|
||||||
} |
|
||||||
|
|
||||||
public JdoUsageException(JDOFatalUserException ex) { |
|
||||||
super(ex.getMessage(), ex); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,328 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2013 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.Properties; |
|
||||||
import javax.jdo.JDOException; |
|
||||||
import javax.jdo.JDOHelper; |
|
||||||
import javax.jdo.PersistenceManagerFactory; |
|
||||||
|
|
||||||
import org.apache.commons.logging.Log; |
|
||||||
import org.apache.commons.logging.LogFactory; |
|
||||||
|
|
||||||
import org.springframework.beans.factory.BeanClassLoaderAware; |
|
||||||
import org.springframework.beans.factory.DisposableBean; |
|
||||||
import org.springframework.beans.factory.FactoryBean; |
|
||||||
import org.springframework.beans.factory.InitializingBean; |
|
||||||
import org.springframework.core.io.Resource; |
|
||||||
import org.springframework.core.io.support.PropertiesLoaderUtils; |
|
||||||
import org.springframework.dao.DataAccessException; |
|
||||||
import org.springframework.dao.support.PersistenceExceptionTranslator; |
|
||||||
import org.springframework.util.CollectionUtils; |
|
||||||
|
|
||||||
/** |
|
||||||
* {@link org.springframework.beans.factory.FactoryBean} that creates a |
|
||||||
* JDO {@link javax.jdo.PersistenceManagerFactory}. This is the usual way to |
|
||||||
* set up a shared JDO PersistenceManagerFactory in a Spring application context; |
|
||||||
* the PersistenceManagerFactory can then be passed to JDO-based DAOs via |
|
||||||
* dependency injection. Note that switching to a JNDI lookup or to a bean-style |
|
||||||
* PersistenceManagerFactory instance is just a matter of configuration! |
|
||||||
* |
|
||||||
* <p><b>NOTE: This class requires JDO 3.0 or higher, as of Spring 4.0.</b> |
|
||||||
* It will also expose the JPA {@link javax.persistence.EntityManagerFactory} as long |
|
||||||
* as the JDO provider creates a {@link javax.jdo.JDOEntityManagerFactory} reference |
|
||||||
* underneath, which means that this class can be used as a replacement for |
|
||||||
* {@link org.springframework.orm.jpa.LocalEntityManagerFactoryBean} in such a scenario. |
|
||||||
* |
|
||||||
* <p>Configuration settings can either be read from a properties file, |
|
||||||
* specified as "configLocation", or locally specified. Properties |
|
||||||
* specified as "jdoProperties" here will override any settings in a file. |
|
||||||
* You may alternatively specify a "persistenceManagerFactoryName", |
|
||||||
* referring to a PMF definition in "META-INF/jdoconfig.xml" |
|
||||||
* (see {@link #setPersistenceManagerFactoryName}). |
|
||||||
* |
|
||||||
* <p>This class also implements the |
|
||||||
* {@link org.springframework.dao.support.PersistenceExceptionTranslator} |
|
||||||
* interface, as autodetected by Spring's |
|
||||||
* {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor}, |
|
||||||
* for AOP-based translation of native exceptions to Spring DataAccessExceptions. |
|
||||||
* Hence, the presence of a LocalPersistenceManagerFactoryBean automatically enables |
|
||||||
* a PersistenceExceptionTranslationPostProcessor to translate JDO exceptions. |
|
||||||
* |
|
||||||
* <p><b>Alternative: Configuration of a PersistenceManagerFactory provider bean</b> |
|
||||||
* |
|
||||||
* <p>As alternative to the properties-driven approach that this FactoryBean offers |
|
||||||
* (which is analogous to using the standard JDOHelper class with a Properties |
|
||||||
* object that is populated with standard JDO properties), you can set up an |
|
||||||
* instance of your PersistenceManagerFactory implementation class directly. |
|
||||||
* |
|
||||||
* <p>Like a DataSource, a PersistenceManagerFactory is encouraged to |
|
||||||
* support bean-style configuration, which makes it very easy to set up as |
|
||||||
* Spring-managed bean. The implementation class becomes the bean class; |
|
||||||
* the remaining properties are applied as bean properties (starting with |
|
||||||
* lower-case characters, in contrast to the corresponding JDO properties). |
|
||||||
* |
|
||||||
* <p>For example, in case of <a href="http://www.jpox.org">JPOX</a>: |
|
||||||
* |
|
||||||
* <p><pre class="code"> |
|
||||||
* <bean id="persistenceManagerFactory" class="org.jpox.PersistenceManagerFactoryImpl" destroy-method="close"> |
|
||||||
* <property name="connectionFactory" ref="dataSource"/> |
|
||||||
* <property name="nontransactionalRead" value="true"/> |
|
||||||
* </bean> |
|
||||||
* </pre> |
|
||||||
* |
|
||||||
* <p>Note that such direct setup of a PersistenceManagerFactory implementation |
|
||||||
* is the only way to pass an external connection factory (i.e. a JDBC DataSource) |
|
||||||
* into a JDO PersistenceManagerFactory. With the standard properties-driven approach, |
|
||||||
* you can only use an internal connection pool or a JNDI DataSource. |
|
||||||
* |
|
||||||
* <p>The {@code close()} method is standardized in JDO; don't forget to |
|
||||||
* specify it as "destroy-method" for any PersistenceManagerFactory instance. |
|
||||||
* Note that this FactoryBean will automatically invoke {@code close()} for |
|
||||||
* the PersistenceManagerFactory that it creates, without any special configuration. |
|
||||||
* |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @since 03.06.2003 |
|
||||||
* @see JdoTransactionManager#setPersistenceManagerFactory |
|
||||||
* @see org.springframework.jndi.JndiObjectFactoryBean |
|
||||||
* @see javax.jdo.JDOHelper#getPersistenceManagerFactory |
|
||||||
* @see javax.jdo.PersistenceManagerFactory#setConnectionFactory |
|
||||||
* @see javax.jdo.PersistenceManagerFactory#close() |
|
||||||
* @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor |
|
||||||
*/ |
|
||||||
public class LocalPersistenceManagerFactoryBean implements FactoryBean<PersistenceManagerFactory>, |
|
||||||
BeanClassLoaderAware, InitializingBean, DisposableBean, PersistenceExceptionTranslator { |
|
||||||
|
|
||||||
protected final Log logger = LogFactory.getLog(getClass()); |
|
||||||
|
|
||||||
private String persistenceManagerFactoryName; |
|
||||||
|
|
||||||
private Resource configLocation; |
|
||||||
|
|
||||||
private final Map<String, Object> jdoPropertyMap = new HashMap<String, Object>(); |
|
||||||
|
|
||||||
private ClassLoader beanClassLoader; |
|
||||||
|
|
||||||
private PersistenceManagerFactory persistenceManagerFactory; |
|
||||||
|
|
||||||
private JdoDialect jdoDialect; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Specify the name of the desired PersistenceManagerFactory. |
|
||||||
* <p>This may either be a properties resource in the classpath if such a resource |
|
||||||
* exists, or a PMF definition with that name from "META-INF/jdoconfig.xml", |
|
||||||
* or a JPA EntityManagerFactory cast to a PersistenceManagerFactory based on the |
|
||||||
* persistence-unit name from "META-INF/persistence.xml" (JPA). |
|
||||||
* <p>Default is none: Either 'persistenceManagerFactoryName' or 'configLocation' |
|
||||||
* or 'jdoProperties' needs to be specified. |
|
||||||
* @see #setConfigLocation |
|
||||||
* @see #setJdoProperties |
|
||||||
*/ |
|
||||||
public void setPersistenceManagerFactoryName(String persistenceManagerFactoryName) { |
|
||||||
this.persistenceManagerFactoryName = persistenceManagerFactoryName; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Set the location of the JDO properties config file, for example |
|
||||||
* as classpath resource "classpath:kodo.properties". |
|
||||||
* <p>Note: Can be omitted when all necessary properties are |
|
||||||
* specified locally via this bean. |
|
||||||
*/ |
|
||||||
public void setConfigLocation(Resource configLocation) { |
|
||||||
this.configLocation = configLocation; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Set JDO properties, such as"javax.jdo.PersistenceManagerFactoryClass". |
|
||||||
* <p>Can be used to override values in a JDO properties config file, |
|
||||||
* or to specify all necessary properties locally. |
|
||||||
* <p>Can be populated with a String "value" (parsed via PropertiesEditor) |
|
||||||
* or a "props" element in XML bean definitions. |
|
||||||
*/ |
|
||||||
public void setJdoProperties(Properties jdoProperties) { |
|
||||||
CollectionUtils.mergePropertiesIntoMap(jdoProperties, this.jdoPropertyMap); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Specify JDO properties as a Map, to be passed into |
|
||||||
* {@code JDOHelper.getPersistenceManagerFactory} (if any). |
|
||||||
* <p>Can be populated with a "map" or "props" element in XML bean definitions. |
|
||||||
* @see javax.jdo.JDOHelper#getPersistenceManagerFactory(java.util.Map) |
|
||||||
*/ |
|
||||||
public void setJdoPropertyMap(Map<String, Object> jdoProperties) { |
|
||||||
if (jdoProperties != null) { |
|
||||||
this.jdoPropertyMap.putAll(jdoProperties); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Allow Map access to the JDO properties to be passed to the JDOHelper, |
|
||||||
* with the option to add or override specific entries. |
|
||||||
* <p>Useful for specifying entries directly, for example via |
|
||||||
* "jdoPropertyMap[myKey]". |
|
||||||
*/ |
|
||||||
public Map<String, Object> getJdoPropertyMap() { |
|
||||||
return this.jdoPropertyMap; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Set the JDO dialect to use for the PersistenceExceptionTranslator |
|
||||||
* functionality of this factory. |
|
||||||
* <p>Default is a DefaultJdoDialect based on the PersistenceManagerFactory's |
|
||||||
* underlying DataSource, if any. |
|
||||||
* @see JdoDialect#translateException |
|
||||||
* @see #translateExceptionIfPossible |
|
||||||
* @see org.springframework.dao.support.PersistenceExceptionTranslator |
|
||||||
*/ |
|
||||||
public void setJdoDialect(JdoDialect jdoDialect) { |
|
||||||
this.jdoDialect = jdoDialect; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setBeanClassLoader(ClassLoader beanClassLoader) { |
|
||||||
this.beanClassLoader = beanClassLoader; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Initialize the PersistenceManagerFactory for the given location. |
|
||||||
* @throws IllegalArgumentException in case of illegal property values |
|
||||||
* @throws IOException if the properties could not be loaded from the given location |
|
||||||
* @throws JDOException in case of JDO initialization errors |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public void afterPropertiesSet() throws IllegalArgumentException, IOException, JDOException { |
|
||||||
if (this.persistenceManagerFactoryName != null) { |
|
||||||
if (this.configLocation != null || !this.jdoPropertyMap.isEmpty()) { |
|
||||||
throw new IllegalStateException("'configLocation'/'jdoProperties' not supported in " + |
|
||||||
"combination with 'persistenceManagerFactoryName' - specify one or the other, not both"); |
|
||||||
} |
|
||||||
if (logger.isInfoEnabled()) { |
|
||||||
logger.info("Building new JDO PersistenceManagerFactory for name '" + |
|
||||||
this.persistenceManagerFactoryName + "'"); |
|
||||||
} |
|
||||||
this.persistenceManagerFactory = newPersistenceManagerFactory(this.persistenceManagerFactoryName); |
|
||||||
} |
|
||||||
|
|
||||||
else { |
|
||||||
Map<String, Object> mergedProps = new HashMap<String, Object>(); |
|
||||||
if (this.configLocation != null) { |
|
||||||
if (logger.isInfoEnabled()) { |
|
||||||
logger.info("Loading JDO config from [" + this.configLocation + "]"); |
|
||||||
} |
|
||||||
CollectionUtils.mergePropertiesIntoMap( |
|
||||||
PropertiesLoaderUtils.loadProperties(this.configLocation), mergedProps); |
|
||||||
} |
|
||||||
mergedProps.putAll(this.jdoPropertyMap); |
|
||||||
logger.info("Building new JDO PersistenceManagerFactory"); |
|
||||||
this.persistenceManagerFactory = newPersistenceManagerFactory(mergedProps); |
|
||||||
} |
|
||||||
|
|
||||||
// Build default JdoDialect if none explicitly specified.
|
|
||||||
if (this.jdoDialect == null) { |
|
||||||
this.jdoDialect = new DefaultJdoDialect(this.persistenceManagerFactory.getConnectionFactory()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Subclasses can override this to perform custom initialization of the |
|
||||||
* PersistenceManagerFactory instance, creating it for the specified name. |
|
||||||
* <p>The default implementation invokes JDOHelper's |
|
||||||
* {@code getPersistenceManagerFactory(String)} method. |
|
||||||
* A custom implementation could prepare the instance in a specific way, |
|
||||||
* or use a custom PersistenceManagerFactory implementation. |
|
||||||
* @param name the name of the desired PersistenceManagerFactory |
|
||||||
* @return the PersistenceManagerFactory instance |
|
||||||
* @see javax.jdo.JDOHelper#getPersistenceManagerFactory(String) |
|
||||||
*/ |
|
||||||
protected PersistenceManagerFactory newPersistenceManagerFactory(String name) { |
|
||||||
return JDOHelper.getPersistenceManagerFactory(name, this.beanClassLoader); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Subclasses can override this to perform custom initialization of the |
|
||||||
* PersistenceManagerFactory instance, creating it via the given Properties |
|
||||||
* that got prepared by this LocalPersistenceManagerFactoryBean. |
|
||||||
* <p>The default implementation invokes JDOHelper's |
|
||||||
* {@code getPersistenceManagerFactory(Map)} method. |
|
||||||
* A custom implementation could prepare the instance in a specific way, |
|
||||||
* or use a custom PersistenceManagerFactory implementation. |
|
||||||
* @param props the merged properties prepared by this LocalPersistenceManagerFactoryBean |
|
||||||
* @return the PersistenceManagerFactory instance |
|
||||||
* @see javax.jdo.JDOHelper#getPersistenceManagerFactory(java.util.Map) |
|
||||||
*/ |
|
||||||
protected PersistenceManagerFactory newPersistenceManagerFactory(Map<?, ?> props) { |
|
||||||
return JDOHelper.getPersistenceManagerFactory(props, this.beanClassLoader); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Return the singleton PersistenceManagerFactory. |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public PersistenceManagerFactory getObject() { |
|
||||||
return this.persistenceManagerFactory; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Class<? extends PersistenceManagerFactory> getObjectType() { |
|
||||||
return (this.persistenceManagerFactory != null ? |
|
||||||
this.persistenceManagerFactory.getClass() : PersistenceManagerFactory.class); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isSingleton() { |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Implementation of the PersistenceExceptionTranslator interface, |
|
||||||
* as autodetected by Spring's PersistenceExceptionTranslationPostProcessor. |
|
||||||
* <p>Converts the exception if it is a JDOException, preferably using a specified |
|
||||||
* JdoDialect. Else returns {@code null} to indicate an unknown exception. |
|
||||||
* @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor |
|
||||||
* @see JdoDialect#translateException |
|
||||||
* @see PersistenceManagerFactoryUtils#convertJdoAccessException |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public DataAccessException translateExceptionIfPossible(RuntimeException ex) { |
|
||||||
if (ex instanceof JDOException) { |
|
||||||
if (this.jdoDialect != null) { |
|
||||||
return this.jdoDialect.translateException((JDOException) ex); |
|
||||||
} |
|
||||||
else { |
|
||||||
return PersistenceManagerFactoryUtils.convertJdoAccessException((JDOException) ex); |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Close the PersistenceManagerFactory on bean factory shutdown. |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public void destroy() { |
|
||||||
logger.info("Closing JDO PersistenceManagerFactory"); |
|
||||||
this.persistenceManagerFactory.close(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,334 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2013 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo; |
|
||||||
|
|
||||||
import javax.jdo.JDODataStoreException; |
|
||||||
import javax.jdo.JDOException; |
|
||||||
import javax.jdo.JDOFatalDataStoreException; |
|
||||||
import javax.jdo.JDOFatalUserException; |
|
||||||
import javax.jdo.JDOObjectNotFoundException; |
|
||||||
import javax.jdo.JDOOptimisticVerificationException; |
|
||||||
import javax.jdo.JDOUserException; |
|
||||||
import javax.jdo.PersistenceManager; |
|
||||||
import javax.jdo.PersistenceManagerFactory; |
|
||||||
import javax.jdo.Query; |
|
||||||
import javax.sql.DataSource; |
|
||||||
|
|
||||||
import org.apache.commons.logging.Log; |
|
||||||
import org.apache.commons.logging.LogFactory; |
|
||||||
|
|
||||||
import org.springframework.core.Ordered; |
|
||||||
import org.springframework.dao.DataAccessException; |
|
||||||
import org.springframework.dao.DataAccessResourceFailureException; |
|
||||||
import org.springframework.jdbc.datasource.DataSourceUtils; |
|
||||||
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator; |
|
||||||
import org.springframework.jdbc.support.SQLExceptionTranslator; |
|
||||||
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator; |
|
||||||
import org.springframework.transaction.support.ResourceHolderSynchronization; |
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager; |
|
||||||
import org.springframework.util.Assert; |
|
||||||
|
|
||||||
/** |
|
||||||
* Helper class featuring methods for JDO {@link PersistenceManager} handling, |
|
||||||
* allowing for reuse of PersistenceManager instances within transactions. |
|
||||||
* Also provides support for exception translation. |
|
||||||
* |
|
||||||
* <p>Used internally by {@link JdoTransactionManager}. |
|
||||||
* Can also be used directly in application code. |
|
||||||
* |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @since 03.06.2003 |
|
||||||
* @see JdoTransactionManager |
|
||||||
* @see org.springframework.transaction.jta.JtaTransactionManager |
|
||||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager |
|
||||||
*/ |
|
||||||
public abstract class PersistenceManagerFactoryUtils { |
|
||||||
|
|
||||||
/** |
|
||||||
* Order value for TransactionSynchronization objects that clean up JDO |
|
||||||
* PersistenceManagers. Return DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100 |
|
||||||
* to execute PersistenceManager cleanup before JDBC Connection cleanup, if any. |
|
||||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#CONNECTION_SYNCHRONIZATION_ORDER |
|
||||||
*/ |
|
||||||
public static final int PERSISTENCE_MANAGER_SYNCHRONIZATION_ORDER = |
|
||||||
DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100; |
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(PersistenceManagerFactoryUtils.class); |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Create an appropriate SQLExceptionTranslator for the given PersistenceManagerFactory. |
|
||||||
* <p>If a DataSource is found, creates a SQLErrorCodeSQLExceptionTranslator for the |
|
||||||
* DataSource; else, falls back to a SQLStateSQLExceptionTranslator. |
|
||||||
* @param connectionFactory the connection factory of the PersistenceManagerFactory |
|
||||||
* (may be {@code null}) |
|
||||||
* @return the SQLExceptionTranslator (never {@code null}) |
|
||||||
* @see javax.jdo.PersistenceManagerFactory#getConnectionFactory() |
|
||||||
* @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator |
|
||||||
* @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator |
|
||||||
*/ |
|
||||||
static SQLExceptionTranslator newJdbcExceptionTranslator(Object connectionFactory) { |
|
||||||
// Check for PersistenceManagerFactory's DataSource.
|
|
||||||
if (connectionFactory instanceof DataSource) { |
|
||||||
return new SQLErrorCodeSQLExceptionTranslator((DataSource) connectionFactory); |
|
||||||
} |
|
||||||
else { |
|
||||||
return new SQLStateSQLExceptionTranslator(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Obtain a JDO PersistenceManager via the given factory. Is aware of a |
|
||||||
* corresponding PersistenceManager bound to the current thread, |
|
||||||
* for example when using JdoTransactionManager. Will create a new |
|
||||||
* PersistenceManager else, if "allowCreate" is {@code true}. |
|
||||||
* @param pmf PersistenceManagerFactory to create the PersistenceManager with |
|
||||||
* @param allowCreate if a non-transactional PersistenceManager should be created |
|
||||||
* when no transactional PersistenceManager can be found for the current thread |
|
||||||
* @return the PersistenceManager |
|
||||||
* @throws DataAccessResourceFailureException if the PersistenceManager couldn't be obtained |
|
||||||
* @throws IllegalStateException if no thread-bound PersistenceManager found and |
|
||||||
* "allowCreate" is {@code false} |
|
||||||
* @see JdoTransactionManager |
|
||||||
*/ |
|
||||||
public static PersistenceManager getPersistenceManager(PersistenceManagerFactory pmf, boolean allowCreate) |
|
||||||
throws DataAccessResourceFailureException, IllegalStateException { |
|
||||||
|
|
||||||
try { |
|
||||||
return doGetPersistenceManager(pmf, allowCreate); |
|
||||||
} |
|
||||||
catch (JDOException ex) { |
|
||||||
throw new DataAccessResourceFailureException("Could not obtain JDO PersistenceManager", ex); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Obtain a JDO PersistenceManager via the given factory. Is aware of a |
|
||||||
* corresponding PersistenceManager bound to the current thread, |
|
||||||
* for example when using JdoTransactionManager. Will create a new |
|
||||||
* PersistenceManager else, if "allowCreate" is {@code true}. |
|
||||||
* <p>Same as {@code getPersistenceManager}, but throwing the original JDOException. |
|
||||||
* @param pmf PersistenceManagerFactory to create the PersistenceManager with |
|
||||||
* @param allowCreate if a non-transactional PersistenceManager should be created |
|
||||||
* when no transactional PersistenceManager can be found for the current thread |
|
||||||
* @return the PersistenceManager |
|
||||||
* @throws JDOException if the PersistenceManager couldn't be created |
|
||||||
* @throws IllegalStateException if no thread-bound PersistenceManager found and |
|
||||||
* "allowCreate" is {@code false} |
|
||||||
* @see #getPersistenceManager(javax.jdo.PersistenceManagerFactory, boolean) |
|
||||||
* @see JdoTransactionManager |
|
||||||
*/ |
|
||||||
public static PersistenceManager doGetPersistenceManager(PersistenceManagerFactory pmf, boolean allowCreate) |
|
||||||
throws JDOException, IllegalStateException { |
|
||||||
|
|
||||||
Assert.notNull(pmf, "No PersistenceManagerFactory specified"); |
|
||||||
|
|
||||||
PersistenceManagerHolder pmHolder = |
|
||||||
(PersistenceManagerHolder) TransactionSynchronizationManager.getResource(pmf); |
|
||||||
if (pmHolder != null) { |
|
||||||
if (!pmHolder.isSynchronizedWithTransaction() && |
|
||||||
TransactionSynchronizationManager.isSynchronizationActive()) { |
|
||||||
pmHolder.setSynchronizedWithTransaction(true); |
|
||||||
TransactionSynchronizationManager.registerSynchronization( |
|
||||||
new PersistenceManagerSynchronization(pmHolder, pmf, false)); |
|
||||||
} |
|
||||||
return pmHolder.getPersistenceManager(); |
|
||||||
} |
|
||||||
|
|
||||||
if (!allowCreate && !TransactionSynchronizationManager.isSynchronizationActive()) { |
|
||||||
throw new IllegalStateException("No JDO PersistenceManager bound to thread, " + |
|
||||||
"and configuration does not allow creation of non-transactional one here"); |
|
||||||
} |
|
||||||
|
|
||||||
logger.debug("Opening JDO PersistenceManager"); |
|
||||||
PersistenceManager pm = pmf.getPersistenceManager(); |
|
||||||
|
|
||||||
if (TransactionSynchronizationManager.isSynchronizationActive()) { |
|
||||||
logger.debug("Registering transaction synchronization for JDO PersistenceManager"); |
|
||||||
// Use same PersistenceManager for further JDO actions within the transaction.
|
|
||||||
// Thread object will get removed by synchronization at transaction completion.
|
|
||||||
pmHolder = new PersistenceManagerHolder(pm); |
|
||||||
pmHolder.setSynchronizedWithTransaction(true); |
|
||||||
TransactionSynchronizationManager.registerSynchronization( |
|
||||||
new PersistenceManagerSynchronization(pmHolder, pmf, true)); |
|
||||||
TransactionSynchronizationManager.bindResource(pmf, pmHolder); |
|
||||||
} |
|
||||||
|
|
||||||
return pm; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Return whether the given JDO PersistenceManager is transactional, that is, |
|
||||||
* bound to the current thread by Spring's transaction facilities. |
|
||||||
* @param pm the JDO PersistenceManager to check |
|
||||||
* @param pmf JDO PersistenceManagerFactory that the PersistenceManager |
|
||||||
* was created with (can be {@code null}) |
|
||||||
* @return whether the PersistenceManager is transactional |
|
||||||
*/ |
|
||||||
public static boolean isPersistenceManagerTransactional( |
|
||||||
PersistenceManager pm, PersistenceManagerFactory pmf) { |
|
||||||
|
|
||||||
if (pmf == null) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
PersistenceManagerHolder pmHolder = |
|
||||||
(PersistenceManagerHolder) TransactionSynchronizationManager.getResource(pmf); |
|
||||||
return (pmHolder != null && pm == pmHolder.getPersistenceManager()); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Apply the current transaction timeout, if any, to the given JDO Query object. |
|
||||||
* @param query the JDO Query object |
|
||||||
* @param pmf JDO PersistenceManagerFactory that the Query was created for |
|
||||||
* @throws JDOException if thrown by JDO methods |
|
||||||
*/ |
|
||||||
public static void applyTransactionTimeout(Query query, PersistenceManagerFactory pmf) throws JDOException { |
|
||||||
Assert.notNull(query, "No Query object specified"); |
|
||||||
PersistenceManagerHolder pmHolder = |
|
||||||
(PersistenceManagerHolder) TransactionSynchronizationManager.getResource(pmf); |
|
||||||
if (pmHolder != null && pmHolder.hasTimeout() && |
|
||||||
pmf.supportedOptions().contains("javax.jdo.option.DatastoreTimeout")) { |
|
||||||
int timeout = (int) pmHolder.getTimeToLiveInMillis(); |
|
||||||
query.setDatastoreReadTimeoutMillis(timeout); |
|
||||||
query.setDatastoreWriteTimeoutMillis(timeout); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Convert the given JDOException to an appropriate exception from the |
|
||||||
* {@code org.springframework.dao} hierarchy. |
|
||||||
* <p>The most important cases like object not found or optimistic locking failure |
|
||||||
* are covered here. For more fine-granular conversion, JdoTransactionManager |
|
||||||
* supports sophisticated translation of exceptions via a JdoDialect. |
|
||||||
* @param ex JDOException that occured |
|
||||||
* @return the corresponding DataAccessException instance |
|
||||||
* @see JdoTransactionManager#convertJdoAccessException |
|
||||||
* @see JdoDialect#translateException |
|
||||||
*/ |
|
||||||
public static DataAccessException convertJdoAccessException(JDOException ex) { |
|
||||||
if (ex instanceof JDOObjectNotFoundException) { |
|
||||||
throw new JdoObjectRetrievalFailureException((JDOObjectNotFoundException) ex); |
|
||||||
} |
|
||||||
if (ex instanceof JDOOptimisticVerificationException) { |
|
||||||
throw new JdoOptimisticLockingFailureException((JDOOptimisticVerificationException) ex); |
|
||||||
} |
|
||||||
if (ex instanceof JDODataStoreException) { |
|
||||||
return new JdoResourceFailureException((JDODataStoreException) ex); |
|
||||||
} |
|
||||||
if (ex instanceof JDOFatalDataStoreException) { |
|
||||||
return new JdoResourceFailureException((JDOFatalDataStoreException) ex); |
|
||||||
} |
|
||||||
if (ex instanceof JDOUserException) { |
|
||||||
return new JdoUsageException((JDOUserException) ex); |
|
||||||
} |
|
||||||
if (ex instanceof JDOFatalUserException) { |
|
||||||
return new JdoUsageException((JDOFatalUserException) ex); |
|
||||||
} |
|
||||||
// fallback
|
|
||||||
return new JdoSystemException(ex); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Close the given PersistenceManager, created via the given factory, |
|
||||||
* if it is not managed externally (i.e. not bound to the thread). |
|
||||||
* @param pm PersistenceManager to close |
|
||||||
* @param pmf PersistenceManagerFactory that the PersistenceManager was created with |
|
||||||
* (can be {@code null}) |
|
||||||
*/ |
|
||||||
public static void releasePersistenceManager(PersistenceManager pm, PersistenceManagerFactory pmf) { |
|
||||||
try { |
|
||||||
doReleasePersistenceManager(pm, pmf); |
|
||||||
} |
|
||||||
catch (JDOException ex) { |
|
||||||
logger.debug("Could not close JDO PersistenceManager", ex); |
|
||||||
} |
|
||||||
catch (Throwable ex) { |
|
||||||
logger.debug("Unexpected exception on closing JDO PersistenceManager", ex); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Actually release a PersistenceManager for the given factory. |
|
||||||
* Same as {@code releasePersistenceManager}, but throwing the original JDOException. |
|
||||||
* @param pm PersistenceManager to close |
|
||||||
* @param pmf PersistenceManagerFactory that the PersistenceManager was created with |
|
||||||
* (can be {@code null}) |
|
||||||
* @throws JDOException if thrown by JDO methods |
|
||||||
*/ |
|
||||||
public static void doReleasePersistenceManager(PersistenceManager pm, PersistenceManagerFactory pmf) |
|
||||||
throws JDOException { |
|
||||||
|
|
||||||
if (pm == null) { |
|
||||||
return; |
|
||||||
} |
|
||||||
// Only release non-transactional PersistenceManagers.
|
|
||||||
if (!isPersistenceManagerTransactional(pm, pmf)) { |
|
||||||
logger.debug("Closing JDO PersistenceManager"); |
|
||||||
pm.close(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Callback for resource cleanup at the end of a non-JDO transaction |
|
||||||
* (e.g. when participating in a JtaTransactionManager transaction). |
|
||||||
* @see org.springframework.transaction.jta.JtaTransactionManager |
|
||||||
*/ |
|
||||||
private static class PersistenceManagerSynchronization |
|
||||||
extends ResourceHolderSynchronization<PersistenceManagerHolder, PersistenceManagerFactory> |
|
||||||
implements Ordered { |
|
||||||
|
|
||||||
private final boolean newPersistenceManager; |
|
||||||
|
|
||||||
public PersistenceManagerSynchronization( |
|
||||||
PersistenceManagerHolder pmHolder, PersistenceManagerFactory pmf, boolean newPersistenceManager) { |
|
||||||
super(pmHolder, pmf); |
|
||||||
this.newPersistenceManager = newPersistenceManager; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int getOrder() { |
|
||||||
return PERSISTENCE_MANAGER_SYNCHRONIZATION_ORDER; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void flushResource(PersistenceManagerHolder resourceHolder) { |
|
||||||
try { |
|
||||||
resourceHolder.getPersistenceManager().flush(); |
|
||||||
} |
|
||||||
catch (JDOException ex) { |
|
||||||
throw convertJdoAccessException(ex); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected boolean shouldUnbindAtCompletion() { |
|
||||||
return this.newPersistenceManager; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected boolean shouldReleaseAfterCompletion(PersistenceManagerHolder resourceHolder) { |
|
||||||
return !resourceHolder.getPersistenceManager().isClosed(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected void releaseResource(PersistenceManagerHolder resourceHolder, PersistenceManagerFactory resourceKey) { |
|
||||||
releasePersistenceManager(resourceHolder.getPersistenceManager(), resourceKey); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,67 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2007 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo; |
|
||||||
|
|
||||||
import javax.jdo.PersistenceManager; |
|
||||||
|
|
||||||
import org.springframework.transaction.support.ResourceHolderSupport; |
|
||||||
import org.springframework.util.Assert; |
|
||||||
|
|
||||||
/** |
|
||||||
* Holder wrapping a JDO PersistenceManager. |
|
||||||
* JdoTransactionManager binds instances of this class
|
|
||||||
* to the thread, for a given PersistenceManagerFactory. |
|
||||||
* |
|
||||||
* <p>Note: This is an SPI class, not intended to be used by applications. |
|
||||||
* |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @since 03.06.2003 |
|
||||||
* @see JdoTransactionManager |
|
||||||
* @see PersistenceManagerFactoryUtils |
|
||||||
*/ |
|
||||||
public class PersistenceManagerHolder extends ResourceHolderSupport { |
|
||||||
|
|
||||||
private final PersistenceManager persistenceManager; |
|
||||||
|
|
||||||
private boolean transactionActive; |
|
||||||
|
|
||||||
|
|
||||||
public PersistenceManagerHolder(PersistenceManager persistenceManager) { |
|
||||||
Assert.notNull(persistenceManager, "PersistenceManager must not be null"); |
|
||||||
this.persistenceManager = persistenceManager; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public PersistenceManager getPersistenceManager() { |
|
||||||
return this.persistenceManager; |
|
||||||
} |
|
||||||
|
|
||||||
protected void setTransactionActive(boolean transactionActive) { |
|
||||||
this.transactionActive = transactionActive; |
|
||||||
} |
|
||||||
|
|
||||||
protected boolean isTransactionActive() { |
|
||||||
return this.transactionActive; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void clear() { |
|
||||||
super.clear(); |
|
||||||
this.transactionActive = false; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,218 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2013 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo; |
|
||||||
|
|
||||||
import java.lang.reflect.InvocationHandler; |
|
||||||
import java.lang.reflect.InvocationTargetException; |
|
||||||
import java.lang.reflect.Method; |
|
||||||
import java.lang.reflect.Proxy; |
|
||||||
import javax.jdo.PersistenceManager; |
|
||||||
import javax.jdo.PersistenceManagerFactory; |
|
||||||
|
|
||||||
import org.springframework.beans.factory.FactoryBean; |
|
||||||
import org.springframework.util.Assert; |
|
||||||
import org.springframework.util.ClassUtils; |
|
||||||
|
|
||||||
/** |
|
||||||
* Proxy for a target JDO {@link javax.jdo.PersistenceManagerFactory}, |
|
||||||
* returning the current thread-bound PersistenceManager (the Spring-managed |
|
||||||
* transactional PersistenceManager or the single OpenPersistenceManagerInView |
|
||||||
* PersistenceManager) on {@code getPersistenceManager()}, if any. |
|
||||||
* |
|
||||||
* <p>Essentially, {@code getPersistenceManager()} calls get seamlessly |
|
||||||
* forwarded to {@link PersistenceManagerFactoryUtils#getPersistenceManager}. |
|
||||||
* Furthermore, {@code PersistenceManager.close} calls get forwarded to |
|
||||||
* {@link PersistenceManagerFactoryUtils#releasePersistenceManager}. |
|
||||||
* |
|
||||||
* <p>The main advantage of this proxy is that it allows DAOs to work with a |
|
||||||
* plain JDO PersistenceManagerFactory reference, while still participating in |
|
||||||
* Spring's (or a J2EE server's) resource and transaction management. DAOs will |
|
||||||
* only rely on the JDO API in such a scenario, without any Spring dependencies. |
|
||||||
* |
|
||||||
* <p>Note that the behavior of this proxy matches the behavior that the JDO spec |
|
||||||
* defines for a PersistenceManagerFactory as exposed by a JCA connector, when |
|
||||||
* deployed in a J2EE server. Hence, DAOs could seamlessly switch between a JNDI |
|
||||||
* PersistenceManagerFactory and this proxy for a local PersistenceManagerFactory, |
|
||||||
* receiving the reference through Dependency Injection. This will work without |
|
||||||
* any Spring API dependencies in the DAO code! |
|
||||||
* |
|
||||||
* <p>Of course, you can still access the target PersistenceManagerFactory |
|
||||||
* even when your DAOs go through this proxy, by defining a bean reference |
|
||||||
* that points directly at your target PersistenceManagerFactory bean. |
|
||||||
* |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @since 1.2 |
|
||||||
* @see javax.jdo.PersistenceManagerFactory#getPersistenceManager() |
|
||||||
* @see javax.jdo.PersistenceManager#close() |
|
||||||
* @see PersistenceManagerFactoryUtils#getPersistenceManager |
|
||||||
* @see PersistenceManagerFactoryUtils#releasePersistenceManager |
|
||||||
*/ |
|
||||||
public class TransactionAwarePersistenceManagerFactoryProxy implements FactoryBean<PersistenceManagerFactory> { |
|
||||||
|
|
||||||
private PersistenceManagerFactory target; |
|
||||||
|
|
||||||
private boolean allowCreate = true; |
|
||||||
|
|
||||||
private PersistenceManagerFactory proxy; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Set the target JDO PersistenceManagerFactory that this proxy should |
|
||||||
* delegate to. This should be the raw PersistenceManagerFactory, as |
|
||||||
* accessed by JdoTransactionManager. |
|
||||||
* @see org.springframework.orm.jdo.JdoTransactionManager |
|
||||||
*/ |
|
||||||
public void setTargetPersistenceManagerFactory(PersistenceManagerFactory target) { |
|
||||||
Assert.notNull(target, "Target PersistenceManagerFactory must not be null"); |
|
||||||
this.target = target; |
|
||||||
Class<?>[] ifcs = ClassUtils.getAllInterfacesForClass(target.getClass(), target.getClass().getClassLoader()); |
|
||||||
this.proxy = (PersistenceManagerFactory) Proxy.newProxyInstance( |
|
||||||
target.getClass().getClassLoader(), ifcs, new PersistenceManagerFactoryInvocationHandler()); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Return the target JDO PersistenceManagerFactory that this proxy delegates to. |
|
||||||
*/ |
|
||||||
public PersistenceManagerFactory getTargetPersistenceManagerFactory() { |
|
||||||
return this.target; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Set whether the PersistenceManagerFactory proxy is allowed to create |
|
||||||
* a non-transactional PersistenceManager when no transactional |
|
||||||
* PersistenceManager can be found for the current thread. |
|
||||||
* <p>Default is "true". Can be turned off to enforce access to |
|
||||||
* transactional PersistenceManagers, which safely allows for DAOs |
|
||||||
* written to get a PersistenceManager without explicit closing |
|
||||||
* (i.e. a {@code PersistenceManagerFactory.getPersistenceManager()} |
|
||||||
* call without corresponding {@code PersistenceManager.close()} call). |
|
||||||
* @see PersistenceManagerFactoryUtils#getPersistenceManager(javax.jdo.PersistenceManagerFactory, boolean) |
|
||||||
*/ |
|
||||||
public void setAllowCreate(boolean allowCreate) { |
|
||||||
this.allowCreate = allowCreate; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Return whether the PersistenceManagerFactory proxy is allowed to create |
|
||||||
* a non-transactional PersistenceManager when no transactional |
|
||||||
* PersistenceManager can be found for the current thread. |
|
||||||
*/ |
|
||||||
protected boolean isAllowCreate() { |
|
||||||
return this.allowCreate; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public PersistenceManagerFactory getObject() { |
|
||||||
return this.proxy; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Class<? extends PersistenceManagerFactory> getObjectType() { |
|
||||||
return PersistenceManagerFactory.class; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isSingleton() { |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Invocation handler that delegates getPersistenceManager calls on the |
|
||||||
* PersistenceManagerFactory proxy to PersistenceManagerFactoryUtils |
|
||||||
* for being aware of thread-bound transactions. |
|
||||||
*/ |
|
||||||
private class PersistenceManagerFactoryInvocationHandler implements InvocationHandler { |
|
||||||
|
|
||||||
@Override |
|
||||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { |
|
||||||
// Invocation on PersistenceManagerFactory interface coming in...
|
|
||||||
|
|
||||||
if (method.getName().equals("equals")) { |
|
||||||
// Only consider equal when proxies are identical.
|
|
||||||
return (proxy == args[0]); |
|
||||||
} |
|
||||||
else if (method.getName().equals("hashCode")) { |
|
||||||
// Use hashCode of PersistenceManagerFactory proxy.
|
|
||||||
return System.identityHashCode(proxy); |
|
||||||
} |
|
||||||
else if (method.getName().equals("getPersistenceManager")) { |
|
||||||
PersistenceManagerFactory target = getTargetPersistenceManagerFactory(); |
|
||||||
PersistenceManager pm = |
|
||||||
PersistenceManagerFactoryUtils.doGetPersistenceManager(target, isAllowCreate()); |
|
||||||
Class<?>[] ifcs = ClassUtils.getAllInterfacesForClass(pm.getClass(), pm.getClass().getClassLoader()); |
|
||||||
return Proxy.newProxyInstance( |
|
||||||
pm.getClass().getClassLoader(), ifcs, new PersistenceManagerInvocationHandler(pm, target)); |
|
||||||
} |
|
||||||
|
|
||||||
// Invoke method on target PersistenceManagerFactory.
|
|
||||||
try { |
|
||||||
return method.invoke(getTargetPersistenceManagerFactory(), args); |
|
||||||
} |
|
||||||
catch (InvocationTargetException ex) { |
|
||||||
throw ex.getTargetException(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Invocation handler that delegates close calls on PersistenceManagers to |
|
||||||
* PersistenceManagerFactoryUtils for being aware of thread-bound transactions. |
|
||||||
*/ |
|
||||||
private static class PersistenceManagerInvocationHandler implements InvocationHandler { |
|
||||||
|
|
||||||
private final PersistenceManager target; |
|
||||||
|
|
||||||
private final PersistenceManagerFactory persistenceManagerFactory; |
|
||||||
|
|
||||||
public PersistenceManagerInvocationHandler(PersistenceManager target, PersistenceManagerFactory pmf) { |
|
||||||
this.target = target; |
|
||||||
this.persistenceManagerFactory = pmf; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { |
|
||||||
// Invocation on PersistenceManager interface coming in...
|
|
||||||
|
|
||||||
if (method.getName().equals("equals")) { |
|
||||||
// Only consider equal when proxies are identical.
|
|
||||||
return (proxy == args[0]); |
|
||||||
} |
|
||||||
else if (method.getName().equals("hashCode")) { |
|
||||||
// Use hashCode of PersistenceManager proxy.
|
|
||||||
return System.identityHashCode(proxy); |
|
||||||
} |
|
||||||
else if (method.getName().equals("close")) { |
|
||||||
// Handle close method: only close if not within a transaction.
|
|
||||||
PersistenceManagerFactoryUtils.doReleasePersistenceManager( |
|
||||||
this.target, this.persistenceManagerFactory); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
// Invoke method on target PersistenceManager.
|
|
||||||
try { |
|
||||||
return method.invoke(this.target, args); |
|
||||||
} |
|
||||||
catch (InvocationTargetException ex) { |
|
||||||
throw ex.getTargetException(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,6 +0,0 @@ |
|||||||
/** |
|
||||||
* Package providing integration of JDO (Java Date Objects) with Spring concepts. |
|
||||||
* Contains PersistenceManagerFactory helper classes, a template plus callback for JDO |
|
||||||
* access, and an implementation of Spring's transaction SPI for local JDO transactions. |
|
||||||
*/ |
|
||||||
package org.springframework.orm.jdo; |
|
||||||
@ -1,161 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2015 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo.support; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import javax.jdo.PersistenceManager; |
|
||||||
import javax.jdo.PersistenceManagerFactory; |
|
||||||
import javax.servlet.FilterChain; |
|
||||||
import javax.servlet.ServletException; |
|
||||||
import javax.servlet.http.HttpServletRequest; |
|
||||||
import javax.servlet.http.HttpServletResponse; |
|
||||||
|
|
||||||
import org.springframework.orm.jdo.PersistenceManagerFactoryUtils; |
|
||||||
import org.springframework.orm.jdo.PersistenceManagerHolder; |
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager; |
|
||||||
import org.springframework.web.context.WebApplicationContext; |
|
||||||
import org.springframework.web.context.support.WebApplicationContextUtils; |
|
||||||
import org.springframework.web.filter.OncePerRequestFilter; |
|
||||||
|
|
||||||
/** |
|
||||||
* Servlet Filter that binds a JDO PersistenceManager to the thread for the |
|
||||||
* entire processing of the request. Intended for the "Open PersistenceManager in |
|
||||||
* View" pattern, i.e. to allow for lazy loading in web views despite the |
|
||||||
* original transactions already being completed. |
|
||||||
* |
|
||||||
* <p>This filter makes JDO PersistenceManagers available via the current thread, |
|
||||||
* which will be autodetected by transaction managers. It is suitable for service |
|
||||||
* layer transactions via {@link org.springframework.orm.jdo.JdoTransactionManager} |
|
||||||
* or {@link org.springframework.transaction.jta.JtaTransactionManager} as well |
|
||||||
* as for non-transactional read-only execution. |
|
||||||
* |
|
||||||
* <p>Looks up the PersistenceManagerFactory in Spring's root web application context. |
|
||||||
* Supports a "persistenceManagerFactoryBeanName" filter init-param in {@code web.xml}; |
|
||||||
* the default bean name is "persistenceManagerFactory". |
|
||||||
* |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @since 1.1 |
|
||||||
* @see OpenPersistenceManagerInViewInterceptor |
|
||||||
* @see org.springframework.orm.jdo.JdoTransactionManager |
|
||||||
* @see org.springframework.orm.jdo.PersistenceManagerFactoryUtils#getPersistenceManager |
|
||||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager |
|
||||||
*/ |
|
||||||
public class OpenPersistenceManagerInViewFilter extends OncePerRequestFilter { |
|
||||||
|
|
||||||
public static final String DEFAULT_PERSISTENCE_MANAGER_FACTORY_BEAN_NAME = "persistenceManagerFactory"; |
|
||||||
|
|
||||||
private String persistenceManagerFactoryBeanName = DEFAULT_PERSISTENCE_MANAGER_FACTORY_BEAN_NAME; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Set the bean name of the PersistenceManagerFactory to fetch from Spring's |
|
||||||
* root application context. Default is "persistenceManagerFactory". |
|
||||||
* @see #DEFAULT_PERSISTENCE_MANAGER_FACTORY_BEAN_NAME |
|
||||||
*/ |
|
||||||
public void setPersistenceManagerFactoryBeanName(String persistenceManagerFactoryBeanName) { |
|
||||||
this.persistenceManagerFactoryBeanName = persistenceManagerFactoryBeanName; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Return the bean name of the PersistenceManagerFactory to fetch from Spring's |
|
||||||
* root application context. |
|
||||||
*/ |
|
||||||
protected String getPersistenceManagerFactoryBeanName() { |
|
||||||
return this.persistenceManagerFactoryBeanName; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Returns "false" so that the filter may re-bind the opened {@code PersistenceManager} |
|
||||||
* to each asynchronously dispatched thread and postpone closing it until the very |
|
||||||
* last asynchronous dispatch. |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
protected boolean shouldNotFilterAsyncDispatch() { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns "false" so that the filter may provide an {@code PersistenceManager} |
|
||||||
* to each error dispatches. |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
protected boolean shouldNotFilterErrorDispatch() { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected void doFilterInternal( |
|
||||||
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) |
|
||||||
throws ServletException, IOException { |
|
||||||
|
|
||||||
PersistenceManagerFactory pmf = lookupPersistenceManagerFactory(request); |
|
||||||
boolean participate = false; |
|
||||||
|
|
||||||
if (TransactionSynchronizationManager.hasResource(pmf)) { |
|
||||||
// Do not modify the PersistenceManager: just set the participate flag.
|
|
||||||
participate = true; |
|
||||||
} |
|
||||||
else { |
|
||||||
logger.debug("Opening JDO PersistenceManager in OpenPersistenceManagerInViewFilter"); |
|
||||||
PersistenceManager pm = PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true); |
|
||||||
TransactionSynchronizationManager.bindResource(pmf, new PersistenceManagerHolder(pm)); |
|
||||||
} |
|
||||||
|
|
||||||
try { |
|
||||||
filterChain.doFilter(request, response); |
|
||||||
} |
|
||||||
|
|
||||||
finally { |
|
||||||
if (!participate) { |
|
||||||
PersistenceManagerHolder pmHolder = (PersistenceManagerHolder) |
|
||||||
TransactionSynchronizationManager.unbindResource(pmf); |
|
||||||
logger.debug("Closing JDO PersistenceManager in OpenPersistenceManagerInViewFilter"); |
|
||||||
PersistenceManagerFactoryUtils.releasePersistenceManager(pmHolder.getPersistenceManager(), pmf); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Look up the PersistenceManagerFactory that this filter should use, |
|
||||||
* taking the current HTTP request as argument. |
|
||||||
* <p>Default implementation delegates to the {@code lookupPersistenceManagerFactory} |
|
||||||
* without arguments. |
|
||||||
* @return the PersistenceManagerFactory to use |
|
||||||
* @see #lookupPersistenceManagerFactory() |
|
||||||
*/ |
|
||||||
protected PersistenceManagerFactory lookupPersistenceManagerFactory(HttpServletRequest request) { |
|
||||||
return lookupPersistenceManagerFactory(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Look up the PersistenceManagerFactory that this filter should use. |
|
||||||
* The default implementation looks for a bean with the specified name |
|
||||||
* in Spring's root application context. |
|
||||||
* @return the PersistenceManagerFactory to use |
|
||||||
* @see #getPersistenceManagerFactoryBeanName |
|
||||||
*/ |
|
||||||
protected PersistenceManagerFactory lookupPersistenceManagerFactory() { |
|
||||||
if (logger.isDebugEnabled()) { |
|
||||||
logger.debug("Using PersistenceManagerFactory '" + getPersistenceManagerFactoryBeanName() + |
|
||||||
"' for OpenPersistenceManagerInViewFilter"); |
|
||||||
} |
|
||||||
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); |
|
||||||
return wac.getBean(getPersistenceManagerFactoryBeanName(), PersistenceManagerFactory.class); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,143 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2013 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo.support; |
|
||||||
|
|
||||||
import javax.jdo.PersistenceManager; |
|
||||||
import javax.jdo.PersistenceManagerFactory; |
|
||||||
|
|
||||||
import org.apache.commons.logging.Log; |
|
||||||
import org.apache.commons.logging.LogFactory; |
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException; |
|
||||||
import org.springframework.orm.jdo.PersistenceManagerFactoryUtils; |
|
||||||
import org.springframework.orm.jdo.PersistenceManagerHolder; |
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager; |
|
||||||
import org.springframework.ui.ModelMap; |
|
||||||
import org.springframework.web.context.request.WebRequest; |
|
||||||
import org.springframework.web.context.request.WebRequestInterceptor; |
|
||||||
|
|
||||||
/** |
|
||||||
* Spring web request interceptor that binds a JDO PersistenceManager to the |
|
||||||
* thread for the entire processing of the request. Intended for the "Open |
|
||||||
* PersistenceManager in View" pattern, i.e. to allow for lazy loading in |
|
||||||
* web views despite the original transactions already being completed. |
|
||||||
* |
|
||||||
* <p>This interceptor makes JDO PersistenceManagers available via the current thread, |
|
||||||
* which will be autodetected by transaction managers. It is suitable for service |
|
||||||
* layer transactions via {@link org.springframework.orm.jdo.JdoTransactionManager} |
|
||||||
* or {@link org.springframework.transaction.jta.JtaTransactionManager} as well |
|
||||||
* as for non-transactional read-only execution. |
|
||||||
* |
|
||||||
* <p>In contrast to {@link OpenPersistenceManagerInViewFilter}, this interceptor |
|
||||||
* is set up in a Spring application context and can thus take advantage of |
|
||||||
* bean wiring. |
|
||||||
* |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @since 1.1 |
|
||||||
* @see OpenPersistenceManagerInViewFilter |
|
||||||
* @see org.springframework.orm.jdo.JdoTransactionManager |
|
||||||
* @see org.springframework.orm.jdo.PersistenceManagerFactoryUtils#getPersistenceManager |
|
||||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager |
|
||||||
*/ |
|
||||||
public class OpenPersistenceManagerInViewInterceptor implements WebRequestInterceptor { |
|
||||||
|
|
||||||
/** |
|
||||||
* Suffix that gets appended to the PersistenceManagerFactory toString |
|
||||||
* representation for the "participate in existing persistence manager |
|
||||||
* handling" request attribute. |
|
||||||
* @see #getParticipateAttributeName |
|
||||||
*/ |
|
||||||
public static final String PARTICIPATE_SUFFIX = ".PARTICIPATE"; |
|
||||||
|
|
||||||
|
|
||||||
protected final Log logger = LogFactory.getLog(getClass()); |
|
||||||
|
|
||||||
private PersistenceManagerFactory persistenceManagerFactory; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Set the JDO PersistenceManagerFactory that should be used to create |
|
||||||
* PersistenceManagers. |
|
||||||
*/ |
|
||||||
public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) { |
|
||||||
this.persistenceManagerFactory = pmf; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Return the JDO PersistenceManagerFactory that should be used to create |
|
||||||
* PersistenceManagers. |
|
||||||
*/ |
|
||||||
public PersistenceManagerFactory getPersistenceManagerFactory() { |
|
||||||
return persistenceManagerFactory; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void preHandle(WebRequest request) throws DataAccessException { |
|
||||||
if (TransactionSynchronizationManager.hasResource(getPersistenceManagerFactory())) { |
|
||||||
// Do not modify the PersistenceManager: just mark the request accordingly.
|
|
||||||
String participateAttributeName = getParticipateAttributeName(); |
|
||||||
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST); |
|
||||||
int newCount = (count != null ? count + 1 : 1); |
|
||||||
request.setAttribute(getParticipateAttributeName(), newCount, WebRequest.SCOPE_REQUEST); |
|
||||||
} |
|
||||||
else { |
|
||||||
logger.debug("Opening JDO PersistenceManager in OpenPersistenceManagerInViewInterceptor"); |
|
||||||
PersistenceManager pm = |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(getPersistenceManagerFactory(), true); |
|
||||||
TransactionSynchronizationManager.bindResource( |
|
||||||
getPersistenceManagerFactory(), new PersistenceManagerHolder(pm)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void postHandle(WebRequest request, ModelMap model) { |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void afterCompletion(WebRequest request, Exception ex) throws DataAccessException { |
|
||||||
String participateAttributeName = getParticipateAttributeName(); |
|
||||||
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST); |
|
||||||
if (count != null) { |
|
||||||
// Do not modify the PersistenceManager: just clear the marker.
|
|
||||||
if (count > 1) { |
|
||||||
request.setAttribute(participateAttributeName, count - 1, WebRequest.SCOPE_REQUEST); |
|
||||||
} |
|
||||||
else { |
|
||||||
request.removeAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST); |
|
||||||
} |
|
||||||
} |
|
||||||
else { |
|
||||||
PersistenceManagerHolder pmHolder = (PersistenceManagerHolder) |
|
||||||
TransactionSynchronizationManager.unbindResource(getPersistenceManagerFactory()); |
|
||||||
logger.debug("Closing JDO PersistenceManager in OpenPersistenceManagerInViewInterceptor"); |
|
||||||
PersistenceManagerFactoryUtils.releasePersistenceManager( |
|
||||||
pmHolder.getPersistenceManager(), getPersistenceManagerFactory()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Return the name of the request attribute that identifies that a request is |
|
||||||
* already filtered. Default implementation takes the toString representation |
|
||||||
* of the PersistenceManagerFactory instance and appends ".FILTERED". |
|
||||||
* @see #PARTICIPATE_SUFFIX |
|
||||||
*/ |
|
||||||
protected String getParticipateAttributeName() { |
|
||||||
return getPersistenceManagerFactory().toString() + PARTICIPATE_SUFFIX; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,230 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2013 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo.support; |
|
||||||
|
|
||||||
import java.lang.reflect.InvocationHandler; |
|
||||||
import java.lang.reflect.InvocationTargetException; |
|
||||||
import java.lang.reflect.Method; |
|
||||||
import java.lang.reflect.Proxy; |
|
||||||
import javax.jdo.PersistenceManager; |
|
||||||
import javax.jdo.PersistenceManagerFactory; |
|
||||||
import javax.jdo.Query; |
|
||||||
|
|
||||||
import org.springframework.beans.factory.FactoryBean; |
|
||||||
import org.springframework.beans.factory.InitializingBean; |
|
||||||
import org.springframework.orm.jdo.DefaultJdoDialect; |
|
||||||
import org.springframework.orm.jdo.JdoDialect; |
|
||||||
import org.springframework.orm.jdo.PersistenceManagerFactoryUtils; |
|
||||||
import org.springframework.util.Assert; |
|
||||||
|
|
||||||
/** |
|
||||||
* Proxy that implements the {@link javax.jdo.PersistenceManager} interface, |
|
||||||
* delegating to the current thread-bound PersistenceManager (the Spring-managed |
|
||||||
* transactional PersistenceManager or the single OpenPersistenceManagerInView |
|
||||||
* PersistenceManager, if any) on each invocation. This class makes such a |
|
||||||
* Spring-style PersistenceManager proxy available for bean references. |
|
||||||
* |
|
||||||
* <p>The main advantage of this proxy is that it allows DAOs to work with a |
|
||||||
* plain JDO PersistenceManager reference in JDO 3.0 style |
|
||||||
* (see {@link javax.jdo.PersistenceManagerFactory#getPersistenceManagerProxy()}), |
|
||||||
* while still participating in Spring's resource and transaction management. |
|
||||||
* |
|
||||||
* <p>The behavior of this proxy matches the behavior that the JDO 3.0 spec |
|
||||||
* defines for a PersistenceManager proxy. Hence, DAOs could seamlessly switch |
|
||||||
* between {@link StandardPersistenceManagerProxyBean} and this Spring-style proxy, |
|
||||||
* receiving the reference through Dependency Injection. This will work without |
|
||||||
* any Spring API dependencies in the DAO code! |
|
||||||
* |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @since 3.0 |
|
||||||
* @see StandardPersistenceManagerProxyBean |
|
||||||
* @see javax.jdo.PersistenceManagerFactory#getPersistenceManagerProxy() |
|
||||||
* @see org.springframework.orm.jdo.PersistenceManagerFactoryUtils#getPersistenceManager |
|
||||||
* @see org.springframework.orm.jdo.PersistenceManagerFactoryUtils#releasePersistenceManager |
|
||||||
*/ |
|
||||||
public class SpringPersistenceManagerProxyBean implements FactoryBean<PersistenceManager>, InitializingBean { |
|
||||||
|
|
||||||
private PersistenceManagerFactory persistenceManagerFactory; |
|
||||||
|
|
||||||
private JdoDialect jdoDialect; |
|
||||||
|
|
||||||
private Class<? extends PersistenceManager> persistenceManagerInterface = PersistenceManager.class; |
|
||||||
|
|
||||||
private boolean allowCreate = true; |
|
||||||
|
|
||||||
private PersistenceManager proxy; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Set the target PersistenceManagerFactory for this proxy. |
|
||||||
*/ |
|
||||||
public void setPersistenceManagerFactory(PersistenceManagerFactory persistenceManagerFactory) { |
|
||||||
this.persistenceManagerFactory = persistenceManagerFactory; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Return the target PersistenceManagerFactory for this proxy. |
|
||||||
*/ |
|
||||||
protected PersistenceManagerFactory getPersistenceManagerFactory() { |
|
||||||
return this.persistenceManagerFactory; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Set the JDO dialect to use for this proxy. |
|
||||||
* <p>Default is a DefaultJdoDialect based on the PersistenceManagerFactory's |
|
||||||
* underlying DataSource, if any. |
|
||||||
*/ |
|
||||||
public void setJdoDialect(JdoDialect jdoDialect) { |
|
||||||
this.jdoDialect = jdoDialect; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Return the JDO dialect to use for this proxy. |
|
||||||
*/ |
|
||||||
protected JdoDialect getJdoDialect() { |
|
||||||
return this.jdoDialect; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Specify the PersistenceManager interface to expose, |
|
||||||
* possibly including vendor extensions. |
|
||||||
* <p>Default is the standard {@code javax.jdo.PersistenceManager} interface. |
|
||||||
*/ |
|
||||||
public void setPersistenceManagerInterface(Class<? extends PersistenceManager> persistenceManagerInterface) { |
|
||||||
this.persistenceManagerInterface = persistenceManagerInterface; |
|
||||||
Assert.notNull(persistenceManagerInterface, "persistenceManagerInterface must not be null"); |
|
||||||
Assert.isAssignable(PersistenceManager.class, persistenceManagerInterface); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Return the PersistenceManager interface to expose. |
|
||||||
*/ |
|
||||||
protected Class<? extends PersistenceManager> getPersistenceManagerInterface() { |
|
||||||
return this.persistenceManagerInterface; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Set whether the PersistenceManagerFactory proxy is allowed to create |
|
||||||
* a non-transactional PersistenceManager when no transactional |
|
||||||
* PersistenceManager can be found for the current thread. |
|
||||||
* <p>Default is "true". Can be turned off to enforce access to |
|
||||||
* transactional PersistenceManagers, which safely allows for DAOs |
|
||||||
* written to get a PersistenceManager without explicit closing |
|
||||||
* (i.e. a {@code PersistenceManagerFactory.getPersistenceManager()} |
|
||||||
* call without corresponding {@code PersistenceManager.close()} call). |
|
||||||
* @see org.springframework.orm.jdo.PersistenceManagerFactoryUtils#getPersistenceManager(javax.jdo.PersistenceManagerFactory, boolean) |
|
||||||
*/ |
|
||||||
public void setAllowCreate(boolean allowCreate) { |
|
||||||
this.allowCreate = allowCreate; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Return whether the PersistenceManagerFactory proxy is allowed to create |
|
||||||
* a non-transactional PersistenceManager when no transactional |
|
||||||
* PersistenceManager can be found for the current thread. |
|
||||||
*/ |
|
||||||
protected boolean isAllowCreate() { |
|
||||||
return this.allowCreate; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void afterPropertiesSet() { |
|
||||||
if (getPersistenceManagerFactory() == null) { |
|
||||||
throw new IllegalArgumentException("Property 'persistenceManagerFactory' is required"); |
|
||||||
} |
|
||||||
// Build default JdoDialect if none explicitly specified.
|
|
||||||
if (this.jdoDialect == null) { |
|
||||||
this.jdoDialect = new DefaultJdoDialect(getPersistenceManagerFactory().getConnectionFactory()); |
|
||||||
} |
|
||||||
this.proxy = (PersistenceManager) Proxy.newProxyInstance( |
|
||||||
getPersistenceManagerFactory().getClass().getClassLoader(), |
|
||||||
new Class<?>[] {getPersistenceManagerInterface()}, new PersistenceManagerInvocationHandler()); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public PersistenceManager getObject() { |
|
||||||
return this.proxy; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Class<? extends PersistenceManager> getObjectType() { |
|
||||||
return getPersistenceManagerInterface(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isSingleton() { |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Invocation handler that delegates close calls on PersistenceManagers to |
|
||||||
* PersistenceManagerFactoryUtils for being aware of thread-bound transactions. |
|
||||||
*/ |
|
||||||
private class PersistenceManagerInvocationHandler implements InvocationHandler { |
|
||||||
|
|
||||||
@Override |
|
||||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { |
|
||||||
// Invocation on PersistenceManager interface coming in...
|
|
||||||
|
|
||||||
if (method.getName().equals("equals")) { |
|
||||||
// Only consider equal when proxies are identical.
|
|
||||||
return (proxy == args[0]); |
|
||||||
} |
|
||||||
else if (method.getName().equals("hashCode")) { |
|
||||||
// Use hashCode of PersistenceManager proxy.
|
|
||||||
return System.identityHashCode(proxy); |
|
||||||
} |
|
||||||
else if (method.getName().equals("toString")) { |
|
||||||
// Deliver toString without touching a target EntityManager.
|
|
||||||
return "Spring PersistenceManager proxy for target factory [" + getPersistenceManagerFactory() + "]"; |
|
||||||
} |
|
||||||
else if (method.getName().equals("getPersistenceManagerFactory")) { |
|
||||||
// Return PersistenceManagerFactory without creating a PersistenceManager.
|
|
||||||
return getPersistenceManagerFactory(); |
|
||||||
} |
|
||||||
else if (method.getName().equals("isClosed")) { |
|
||||||
// Proxy is always usable.
|
|
||||||
return false; |
|
||||||
} |
|
||||||
else if (method.getName().equals("close")) { |
|
||||||
// Suppress close method.
|
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
// Invoke method on target PersistenceManager.
|
|
||||||
PersistenceManager pm = PersistenceManagerFactoryUtils.doGetPersistenceManager( |
|
||||||
getPersistenceManagerFactory(), isAllowCreate()); |
|
||||||
try { |
|
||||||
Object retVal = method.invoke(pm, args); |
|
||||||
if (retVal instanceof Query) { |
|
||||||
PersistenceManagerFactoryUtils.applyTransactionTimeout( |
|
||||||
(Query) retVal, getPersistenceManagerFactory()); |
|
||||||
} |
|
||||||
return retVal; |
|
||||||
} |
|
||||||
catch (InvocationTargetException ex) { |
|
||||||
throw ex.getTargetException(); |
|
||||||
} |
|
||||||
finally { |
|
||||||
PersistenceManagerFactoryUtils.doReleasePersistenceManager(pm, getPersistenceManagerFactory()); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,73 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2013 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either exprShess or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo.support; |
|
||||||
|
|
||||||
import javax.jdo.PersistenceManager; |
|
||||||
import javax.jdo.PersistenceManagerFactory; |
|
||||||
|
|
||||||
import org.springframework.beans.factory.FactoryBean; |
|
||||||
import org.springframework.util.Assert; |
|
||||||
|
|
||||||
/** |
|
||||||
* Proxy that implements the {@link javax.jdo.PersistenceManager} interface, |
|
||||||
* delegating to a thread-bound PersistenceManager on each invocation - |
|
||||||
* as defined by the JDO 3.0 specification. This class makes such a standard |
|
||||||
* JDO PersistenceManager proxy available for bean references. |
|
||||||
* |
|
||||||
* <p>The main advantage of this proxy is that it allows DAOs to work with a |
|
||||||
* plain JDO PersistenceManager reference in JDO 3.0 style |
|
||||||
* (see {@link javax.jdo.PersistenceManagerFactory#getPersistenceManagerProxy()}), |
|
||||||
* exposing the exact behavior that the target JDO provider implements. |
|
||||||
* |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @since 3.0 |
|
||||||
* @see SpringPersistenceManagerProxyBean |
|
||||||
* @see javax.jdo.PersistenceManagerFactory#getPersistenceManagerProxy() |
|
||||||
*/ |
|
||||||
public class StandardPersistenceManagerProxyBean implements FactoryBean<PersistenceManager> { |
|
||||||
|
|
||||||
private PersistenceManager proxy; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Set the target JDO PersistenceManagerFactory that this proxy should |
|
||||||
* delegate to. This should be the raw PersistenceManagerFactory, as |
|
||||||
* accessed by JdoTransactionManager. |
|
||||||
* @see org.springframework.orm.jdo.JdoTransactionManager |
|
||||||
*/ |
|
||||||
public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) { |
|
||||||
Assert.notNull(pmf, "PersistenceManagerFactory must not be null"); |
|
||||||
this.proxy = pmf.getPersistenceManagerProxy(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public PersistenceManager getObject() { |
|
||||||
return this.proxy; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Class<? extends PersistenceManager> getObjectType() { |
|
||||||
return (this.proxy != null ? this.proxy.getClass() : PersistenceManager.class); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isSingleton() { |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,5 +0,0 @@ |
|||||||
/** |
|
||||||
* Classes supporting the {@code org.springframework.orm.jdo} package. |
|
||||||
*/ |
|
||||||
package org.springframework.orm.jdo.support; |
|
||||||
|
|
||||||
@ -1,7 +1,7 @@ |
|||||||
<html> |
<html> |
||||||
<body> |
<body> |
||||||
<p> |
<p> |
||||||
Spring's O/R Mapping package: supporting Hibernate, JPA, JDO, and iBATIS SQL Maps. |
Spring's O/R Mapping package: supporting JPA as well as native Hibernate. |
||||||
</p> |
</p> |
||||||
</body> |
</body> |
||||||
</html> |
</html> |
||||||
@ -1,796 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2013 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo; |
|
||||||
|
|
||||||
import java.sql.Connection; |
|
||||||
import java.sql.DatabaseMetaData; |
|
||||||
import java.sql.SQLException; |
|
||||||
import java.sql.Savepoint; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
import javax.jdo.Constants; |
|
||||||
import javax.jdo.JDOFatalDataStoreException; |
|
||||||
import javax.jdo.PersistenceManager; |
|
||||||
import javax.jdo.PersistenceManagerFactory; |
|
||||||
import javax.jdo.Transaction; |
|
||||||
import javax.sql.DataSource; |
|
||||||
import javax.transaction.Status; |
|
||||||
import javax.transaction.TransactionManager; |
|
||||||
import javax.transaction.UserTransaction; |
|
||||||
|
|
||||||
import org.junit.After; |
|
||||||
import org.junit.Before; |
|
||||||
import org.junit.Test; |
|
||||||
|
|
||||||
import org.springframework.jdbc.datasource.ConnectionHandle; |
|
||||||
import org.springframework.jdbc.datasource.ConnectionHolder; |
|
||||||
import org.springframework.jdbc.datasource.SimpleConnectionHandle; |
|
||||||
import org.springframework.orm.jdo.support.SpringPersistenceManagerProxyBean; |
|
||||||
import org.springframework.orm.jdo.support.StandardPersistenceManagerProxyBean; |
|
||||||
import org.springframework.tests.transaction.MockJtaTransaction; |
|
||||||
import org.springframework.transaction.PlatformTransactionManager; |
|
||||||
import org.springframework.transaction.TransactionDefinition; |
|
||||||
import org.springframework.transaction.TransactionStatus; |
|
||||||
import org.springframework.transaction.jta.JtaTransactionManager; |
|
||||||
import org.springframework.transaction.support.TransactionCallback; |
|
||||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult; |
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager; |
|
||||||
import org.springframework.transaction.support.TransactionTemplate; |
|
||||||
|
|
||||||
import static org.junit.Assert.*; |
|
||||||
import static org.mockito.BDDMockito.*; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @author Phillip Webb |
|
||||||
*/ |
|
||||||
public class JdoTransactionManagerTests { |
|
||||||
|
|
||||||
private PersistenceManagerFactory pmf; |
|
||||||
|
|
||||||
private PersistenceManager pm; |
|
||||||
|
|
||||||
private Transaction tx; |
|
||||||
|
|
||||||
|
|
||||||
@Before |
|
||||||
public void setUp() { |
|
||||||
pmf = mock(PersistenceManagerFactory.class); |
|
||||||
pm = mock(PersistenceManager.class); |
|
||||||
tx = mock(Transaction.class); |
|
||||||
} |
|
||||||
|
|
||||||
@After |
|
||||||
public void tearDown() { |
|
||||||
assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); |
|
||||||
assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); |
|
||||||
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); |
|
||||||
assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testTransactionCommit() { |
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
given(pmf.getPersistenceManagerProxy()).willReturn(pm); |
|
||||||
given(pm.currentTransaction()).willReturn(tx); |
|
||||||
|
|
||||||
PlatformTransactionManager tm = new JdoTransactionManager(pmf); |
|
||||||
TransactionTemplate tt = new TransactionTemplate(tm); |
|
||||||
final List l = new ArrayList(); |
|
||||||
l.add("test"); |
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); |
|
||||||
|
|
||||||
Object result = tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
|
|
||||||
TransactionAwarePersistenceManagerFactoryProxy proxyFactory = |
|
||||||
new TransactionAwarePersistenceManagerFactoryProxy(); |
|
||||||
proxyFactory.setTargetPersistenceManagerFactory(pmf); |
|
||||||
PersistenceManagerFactory pmfProxy = proxyFactory.getObject(); |
|
||||||
assertEquals(pm.toString(), pmfProxy.getPersistenceManager().toString()); |
|
||||||
pmfProxy.getPersistenceManager().flush(); |
|
||||||
pmfProxy.getPersistenceManager().close(); |
|
||||||
|
|
||||||
SpringPersistenceManagerProxyBean proxyBean = new SpringPersistenceManagerProxyBean(); |
|
||||||
proxyBean.setPersistenceManagerFactory(pmf); |
|
||||||
proxyBean.afterPropertiesSet(); |
|
||||||
PersistenceManager pmProxy = proxyBean.getObject(); |
|
||||||
assertSame(pmf, pmProxy.getPersistenceManagerFactory()); |
|
||||||
pmProxy.flush(); |
|
||||||
pmProxy.close(); |
|
||||||
|
|
||||||
StandardPersistenceManagerProxyBean stdProxyBean = new StandardPersistenceManagerProxyBean(); |
|
||||||
stdProxyBean.setPersistenceManagerFactory(pmf); |
|
||||||
PersistenceManager stdPmProxy = stdProxyBean.getObject(); |
|
||||||
stdPmProxy.flush(); |
|
||||||
|
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true).flush(); |
|
||||||
return l; |
|
||||||
} |
|
||||||
}); |
|
||||||
assertTrue("Correct result list", result == l); |
|
||||||
|
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); |
|
||||||
|
|
||||||
verify(pm, times(4)).flush(); |
|
||||||
verify(pm).close(); |
|
||||||
verify(tx).begin(); |
|
||||||
verify(tx).commit(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testTransactionRollback() { |
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
given(pm.currentTransaction()).willReturn(tx); |
|
||||||
given(tx.isActive()).willReturn(true); |
|
||||||
|
|
||||||
PlatformTransactionManager tm = new JdoTransactionManager(pmf); |
|
||||||
TransactionTemplate tt = new TransactionTemplate(tm); |
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); |
|
||||||
|
|
||||||
try { |
|
||||||
tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true); |
|
||||||
throw new RuntimeException("application exception"); |
|
||||||
} |
|
||||||
}); |
|
||||||
fail("Should have thrown RuntimeException"); |
|
||||||
} |
|
||||||
catch (RuntimeException ex) { |
|
||||||
// expected
|
|
||||||
} |
|
||||||
|
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); |
|
||||||
|
|
||||||
verify(pm).close(); |
|
||||||
verify(tx).begin(); |
|
||||||
verify(tx).rollback(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testTransactionRollbackWithAlreadyRolledBack() { |
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
given(pm.currentTransaction()).willReturn(tx); |
|
||||||
|
|
||||||
PlatformTransactionManager tm = new JdoTransactionManager(pmf); |
|
||||||
TransactionTemplate tt = new TransactionTemplate(tm); |
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); |
|
||||||
|
|
||||||
try { |
|
||||||
tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true); |
|
||||||
throw new RuntimeException("application exception"); |
|
||||||
} |
|
||||||
}); |
|
||||||
fail("Should have thrown RuntimeException"); |
|
||||||
} |
|
||||||
catch (RuntimeException ex) { |
|
||||||
// expected
|
|
||||||
} |
|
||||||
|
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); |
|
||||||
|
|
||||||
verify(pm).close(); |
|
||||||
verify(tx).begin(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testTransactionRollbackOnly() { |
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
given(pm.currentTransaction()).willReturn(tx); |
|
||||||
given(tx.isActive()).willReturn(true); |
|
||||||
|
|
||||||
PlatformTransactionManager tm = new JdoTransactionManager(pmf); |
|
||||||
TransactionTemplate tt = new TransactionTemplate(tm); |
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
|
|
||||||
tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true).flush(); |
|
||||||
status.setRollbackOnly(); |
|
||||||
return null; |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
|
|
||||||
verify(pm).flush(); |
|
||||||
verify(pm).close(); |
|
||||||
verify(tx).begin(); |
|
||||||
verify(tx).rollback(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testParticipatingTransactionWithCommit() { |
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
given(pm.currentTransaction()).willReturn(tx); |
|
||||||
given(tx.isActive()).willReturn(true); |
|
||||||
|
|
||||||
PlatformTransactionManager tm = new JdoTransactionManager(pmf); |
|
||||||
final TransactionTemplate tt = new TransactionTemplate(tm); |
|
||||||
final List l = new ArrayList(); |
|
||||||
l.add("test"); |
|
||||||
|
|
||||||
Object result = tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
|
|
||||||
return tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true).flush(); |
|
||||||
return l; |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
}); |
|
||||||
assertTrue("Correct result list", result == l); |
|
||||||
|
|
||||||
verify(pm).flush(); |
|
||||||
verify(pm).close(); |
|
||||||
verify(tx).begin(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testParticipatingTransactionWithRollback() { |
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
given(pm.currentTransaction()).willReturn(tx); |
|
||||||
given(tx.isActive()).willReturn(true); |
|
||||||
|
|
||||||
PlatformTransactionManager tm = new JdoTransactionManager(pmf); |
|
||||||
final TransactionTemplate tt = new TransactionTemplate(tm); |
|
||||||
try { |
|
||||||
tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
return tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true); |
|
||||||
throw new RuntimeException("application exception"); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
}); |
|
||||||
fail("Should have thrown RuntimeException"); |
|
||||||
} |
|
||||||
catch (RuntimeException ex) { |
|
||||||
// expected
|
|
||||||
} |
|
||||||
verify(pm).close(); |
|
||||||
verify(tx).begin(); |
|
||||||
verify(tx).setRollbackOnly(); |
|
||||||
verify(tx).rollback(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testParticipatingTransactionWithRollbackOnly() { |
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
given(pm.currentTransaction()).willReturn(tx); |
|
||||||
given(tx.isActive()).willReturn(true); |
|
||||||
given(tx.getRollbackOnly()).willReturn(true); |
|
||||||
willThrow(new JDOFatalDataStoreException()).given(tx).commit(); |
|
||||||
|
|
||||||
PlatformTransactionManager tm = new JdoTransactionManager(pmf); |
|
||||||
final TransactionTemplate tt = new TransactionTemplate(tm); |
|
||||||
final List l = new ArrayList(); |
|
||||||
l.add("test"); |
|
||||||
|
|
||||||
try { |
|
||||||
tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
return tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true).flush(); |
|
||||||
status.setRollbackOnly(); |
|
||||||
return null; |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
}); |
|
||||||
fail("Should have thrown JdoResourceFailureException"); |
|
||||||
} |
|
||||||
catch (JdoResourceFailureException ex) { |
|
||||||
// expected
|
|
||||||
} |
|
||||||
verify(pm).flush(); |
|
||||||
verify(pm).close(); |
|
||||||
verify(tx).begin(); |
|
||||||
verify(tx).setRollbackOnly(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testParticipatingTransactionWithWithRequiresNew() { |
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
given(pm.currentTransaction()).willReturn(tx); |
|
||||||
given(tx.isActive()).willReturn(true); |
|
||||||
|
|
||||||
PlatformTransactionManager tm = new JdoTransactionManager(pmf); |
|
||||||
final TransactionTemplate tt = new TransactionTemplate(tm); |
|
||||||
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); |
|
||||||
final List l = new ArrayList(); |
|
||||||
l.add("test"); |
|
||||||
|
|
||||||
Object result = tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
return tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true).flush(); |
|
||||||
return l; |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
}); |
|
||||||
assertTrue("Correct result list", result == l); |
|
||||||
verify(tx, times(2)).begin(); |
|
||||||
verify(tx, times(2)).commit(); |
|
||||||
verify(pm).flush(); |
|
||||||
verify(pm, times(2)).close(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testParticipatingTransactionWithWithRequiresNewAndPrebound() { |
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
given(pm.currentTransaction()).willReturn(tx); |
|
||||||
given(tx.isActive()).willReturn(true); |
|
||||||
|
|
||||||
PlatformTransactionManager tm = new JdoTransactionManager(pmf); |
|
||||||
final TransactionTemplate tt = new TransactionTemplate(tm); |
|
||||||
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); |
|
||||||
final List l = new ArrayList(); |
|
||||||
l.add("test"); |
|
||||||
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); |
|
||||||
TransactionSynchronizationManager.bindResource(pmf, new PersistenceManagerHolder(pm)); |
|
||||||
assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
|
|
||||||
Object result = tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true); |
|
||||||
|
|
||||||
return tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true).flush(); |
|
||||||
return l; |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
}); |
|
||||||
assertTrue("Correct result list", result == l); |
|
||||||
|
|
||||||
assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
TransactionSynchronizationManager.unbindResource(pmf); |
|
||||||
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); |
|
||||||
|
|
||||||
verify(tx, times(2)).begin(); |
|
||||||
verify(tx, times(2)).commit(); |
|
||||||
verify(pm).flush(); |
|
||||||
verify(pm).close(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testJtaTransactionCommit() throws Exception { |
|
||||||
UserTransaction ut = mock(UserTransaction.class); |
|
||||||
given(ut.getStatus()).willReturn(Status.STATUS_NO_TRANSACTION, Status.STATUS_ACTIVE); |
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
|
|
||||||
JtaTransactionManager ptm = new JtaTransactionManager(ut); |
|
||||||
TransactionTemplate tt = new TransactionTemplate(ptm); |
|
||||||
final List l = new ArrayList(); |
|
||||||
l.add("test"); |
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); |
|
||||||
|
|
||||||
Object result = tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); |
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true).flush(); |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true).flush(); |
|
||||||
assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
return l; |
|
||||||
} |
|
||||||
}); |
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("Correct result list", result == l); |
|
||||||
|
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); |
|
||||||
|
|
||||||
verify(ut).begin(); |
|
||||||
verify(ut).commit(); |
|
||||||
verify(pm, times(2)).flush(); |
|
||||||
verify(pm, times(2)).close(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testParticipatingJtaTransactionWithWithRequiresNewAndPrebound() throws Exception { |
|
||||||
final UserTransaction ut = mock(UserTransaction.class); |
|
||||||
final TransactionManager tm = mock(TransactionManager.class); |
|
||||||
|
|
||||||
given(ut.getStatus()).willReturn(Status.STATUS_NO_TRANSACTION, |
|
||||||
Status.STATUS_ACTIVE, Status.STATUS_ACTIVE, Status.STATUS_ACTIVE, |
|
||||||
Status.STATUS_ACTIVE, Status.STATUS_ACTIVE); |
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
|
|
||||||
JtaTransactionManager ptm = new JtaTransactionManager(ut, tm); |
|
||||||
final TransactionTemplate tt = new TransactionTemplate(ptm); |
|
||||||
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); |
|
||||||
final List l = new ArrayList(); |
|
||||||
l.add("test"); |
|
||||||
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); |
|
||||||
TransactionSynchronizationManager.bindResource(pmf, new PersistenceManagerHolder(pm)); |
|
||||||
assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
|
|
||||||
Object result = tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
try { |
|
||||||
MockJtaTransaction transaction = new MockJtaTransaction(); |
|
||||||
given(tm.suspend()).willReturn(transaction); |
|
||||||
} |
|
||||||
catch (Exception ex) { |
|
||||||
} |
|
||||||
|
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true); |
|
||||||
|
|
||||||
return tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true).flush(); |
|
||||||
return l; |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
}); |
|
||||||
assertTrue("Correct result list", result == l); |
|
||||||
|
|
||||||
assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
TransactionSynchronizationManager.unbindResource(pmf); |
|
||||||
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); |
|
||||||
|
|
||||||
verify(ut, times(2)).begin(); |
|
||||||
verify(pm).flush(); |
|
||||||
verify(pm, times(2)).close(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testTransactionCommitWithPropagationSupports() { |
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
|
|
||||||
PlatformTransactionManager tm = new JdoTransactionManager(pmf); |
|
||||||
TransactionTemplate tt = new TransactionTemplate(tm); |
|
||||||
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); |
|
||||||
final List l = new ArrayList(); |
|
||||||
l.add("test"); |
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
|
|
||||||
Object result = tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("Is not new transaction", !status.isNewTransaction()); |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true); |
|
||||||
return l; |
|
||||||
} |
|
||||||
}); |
|
||||||
assertTrue("Correct result list", result == l); |
|
||||||
|
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
|
|
||||||
verify(pm, times(2)).close(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testIsolationLevel() { |
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
given(pm.currentTransaction()).willReturn(tx); |
|
||||||
|
|
||||||
PlatformTransactionManager tm = new JdoTransactionManager(pmf); |
|
||||||
TransactionTemplate tt = new TransactionTemplate(tm); |
|
||||||
tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE); |
|
||||||
tt.execute(new TransactionCallbackWithoutResult() { |
|
||||||
@Override |
|
||||||
protected void doInTransactionWithoutResult(TransactionStatus status) { |
|
||||||
} |
|
||||||
}); |
|
||||||
verify(tx).setIsolationLevel(Constants.TX_SERIALIZABLE); |
|
||||||
verify(pm).close(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testTransactionCommitWithPrebound() { |
|
||||||
given(pm.currentTransaction()).willReturn(tx); |
|
||||||
|
|
||||||
PlatformTransactionManager tm = new JdoTransactionManager(pmf); |
|
||||||
TransactionTemplate tt = new TransactionTemplate(tm); |
|
||||||
final List l = new ArrayList(); |
|
||||||
l.add("test"); |
|
||||||
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); |
|
||||||
TransactionSynchronizationManager.bindResource(pmf, new PersistenceManagerHolder(pm)); |
|
||||||
assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
|
|
||||||
Object result = tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true); |
|
||||||
return l; |
|
||||||
} |
|
||||||
}); |
|
||||||
assertTrue("Correct result list", result == l); |
|
||||||
|
|
||||||
assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
TransactionSynchronizationManager.unbindResource(pmf); |
|
||||||
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); |
|
||||||
|
|
||||||
verify(tx).begin(); |
|
||||||
verify(tx).commit(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testTransactionCommitWithDataSource() throws SQLException { |
|
||||||
final DataSource ds = mock(DataSource.class); |
|
||||||
JdoDialect dialect = mock(JdoDialect.class); |
|
||||||
final Connection con = mock(Connection.class); |
|
||||||
ConnectionHandle conHandle = new SimpleConnectionHandle(con); |
|
||||||
|
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
given(pm.currentTransaction()).willReturn(tx); |
|
||||||
TransactionTemplate tt = new TransactionTemplate(); |
|
||||||
given(dialect.getJdbcConnection(pm, false)).willReturn(conHandle); |
|
||||||
|
|
||||||
JdoTransactionManager tm = new JdoTransactionManager(); |
|
||||||
tm.setPersistenceManagerFactory(pmf); |
|
||||||
tm.setDataSource(ds); |
|
||||||
tm.setJdoDialect(dialect); |
|
||||||
tt.setTransactionManager(tm); |
|
||||||
final List l = new ArrayList(); |
|
||||||
l.add("test"); |
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
|
|
||||||
Object result = tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("Has thread con", TransactionSynchronizationManager.hasResource(ds)); |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true); |
|
||||||
return l; |
|
||||||
} |
|
||||||
}); |
|
||||||
assertTrue("Correct result list", result == l); |
|
||||||
|
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("Hasn't thread con", !TransactionSynchronizationManager.hasResource(ds)); |
|
||||||
|
|
||||||
verify(pm).close(); |
|
||||||
verify(dialect).beginTransaction(tx, tt); |
|
||||||
verify(dialect).releaseJdbcConnection(conHandle, pm); |
|
||||||
verify(dialect).cleanupTransaction(null); |
|
||||||
verify(tx).commit(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testTransactionCommitWithAutoDetectedDataSource() throws SQLException { |
|
||||||
final DataSource ds = mock(DataSource.class); |
|
||||||
JdoDialect dialect = mock(JdoDialect.class); |
|
||||||
final Connection con = mock(Connection.class); |
|
||||||
ConnectionHandle conHandle = new SimpleConnectionHandle(con); |
|
||||||
|
|
||||||
given(pmf.getConnectionFactory()).willReturn(ds); |
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
given(pm.currentTransaction()).willReturn(tx); |
|
||||||
TransactionTemplate tt = new TransactionTemplate(); |
|
||||||
given(dialect.getJdbcConnection(pm, false)).willReturn(conHandle); |
|
||||||
|
|
||||||
JdoTransactionManager tm = new JdoTransactionManager(); |
|
||||||
tm.setPersistenceManagerFactory(pmf); |
|
||||||
tm.setJdoDialect(dialect); |
|
||||||
tm.afterPropertiesSet(); |
|
||||||
tt.setTransactionManager(tm); |
|
||||||
final List l = new ArrayList(); |
|
||||||
l.add("test"); |
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
|
|
||||||
Object result = tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("Has thread con", TransactionSynchronizationManager.hasResource(ds)); |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true); |
|
||||||
return l; |
|
||||||
} |
|
||||||
}); |
|
||||||
assertTrue("Correct result list", result == l); |
|
||||||
|
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("Hasn't thread con", !TransactionSynchronizationManager.hasResource(ds)); |
|
||||||
|
|
||||||
verify(pm).close(); |
|
||||||
verify(dialect).beginTransaction(tx, tt); |
|
||||||
verify(dialect).releaseJdbcConnection(conHandle, pm); |
|
||||||
verify(dialect).cleanupTransaction(null); |
|
||||||
verify(tx).commit(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testTransactionCommitWithAutoDetectedDataSourceAndNoConnection() throws SQLException { |
|
||||||
final DataSource ds = mock(DataSource.class); |
|
||||||
final JdoDialect dialect = mock(JdoDialect.class); |
|
||||||
|
|
||||||
given(pmf.getConnectionFactory()).willReturn(ds); |
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
given(pm.currentTransaction()).willReturn(tx); |
|
||||||
TransactionTemplate tt = new TransactionTemplate(); |
|
||||||
given(dialect.getJdbcConnection(pm, false)).willReturn(null); |
|
||||||
|
|
||||||
JdoTransactionManager tm = new JdoTransactionManager(); |
|
||||||
tm.setPersistenceManagerFactory(pmf); |
|
||||||
tm.setJdoDialect(dialect); |
|
||||||
tm.afterPropertiesSet(); |
|
||||||
tt.setTransactionManager(tm); |
|
||||||
final List l = new ArrayList(); |
|
||||||
l.add("test"); |
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
|
|
||||||
Object result = tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("Hasn't thread con", !TransactionSynchronizationManager.hasResource(ds)); |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true).flush(); |
|
||||||
return l; |
|
||||||
} |
|
||||||
}); |
|
||||||
assertTrue("Correct result list", result == l); |
|
||||||
|
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("Hasn't thread con", !TransactionSynchronizationManager.hasResource(ds)); |
|
||||||
|
|
||||||
verify(pm).flush(); |
|
||||||
verify(pm).close(); |
|
||||||
verify(dialect).beginTransaction(tx, tt); |
|
||||||
verify(dialect).cleanupTransaction(null); |
|
||||||
verify(tx).commit(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testExistingTransactionWithPropagationNestedAndRollback() throws SQLException { |
|
||||||
doTestExistingTransactionWithPropagationNestedAndRollback(false); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testExistingTransactionWithManualSavepointAndRollback() throws SQLException { |
|
||||||
doTestExistingTransactionWithPropagationNestedAndRollback(true); |
|
||||||
} |
|
||||||
|
|
||||||
private void doTestExistingTransactionWithPropagationNestedAndRollback(final boolean manualSavepoint) |
|
||||||
throws SQLException { |
|
||||||
|
|
||||||
final DataSource ds = mock(DataSource.class); |
|
||||||
JdoDialect dialect = mock(JdoDialect.class); |
|
||||||
final Connection con = mock(Connection.class); |
|
||||||
DatabaseMetaData md = mock(DatabaseMetaData.class); |
|
||||||
Savepoint sp = mock(Savepoint.class); |
|
||||||
|
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
given(pm.currentTransaction()).willReturn(tx); |
|
||||||
given(md.supportsSavepoints()).willReturn(true); |
|
||||||
given(con.getMetaData()).willReturn(md); |
|
||||||
given(con.setSavepoint(ConnectionHolder.SAVEPOINT_NAME_PREFIX + 1)).willReturn(sp); |
|
||||||
final TransactionTemplate tt = new TransactionTemplate(); |
|
||||||
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED); |
|
||||||
ConnectionHandle conHandle = new SimpleConnectionHandle(con); |
|
||||||
given(dialect.getJdbcConnection(pm, false)).willReturn(conHandle); |
|
||||||
given(tx.isActive()).willReturn(!manualSavepoint); |
|
||||||
|
|
||||||
JdoTransactionManager tm = new JdoTransactionManager(); |
|
||||||
tm.setNestedTransactionAllowed(true); |
|
||||||
tm.setPersistenceManagerFactory(pmf); |
|
||||||
tm.setDataSource(ds); |
|
||||||
tm.setJdoDialect(dialect); |
|
||||||
tt.setTransactionManager(tm); |
|
||||||
final List l = new ArrayList(); |
|
||||||
l.add("test"); |
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
|
|
||||||
Object result = tt.execute(new TransactionCallback() { |
|
||||||
@Override |
|
||||||
public Object doInTransaction(TransactionStatus status) { |
|
||||||
assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("Has thread con", TransactionSynchronizationManager.hasResource(ds)); |
|
||||||
if (manualSavepoint) { |
|
||||||
Object savepoint = status.createSavepoint(); |
|
||||||
status.rollbackToSavepoint(savepoint); |
|
||||||
} |
|
||||||
else { |
|
||||||
tt.execute(new TransactionCallbackWithoutResult() { |
|
||||||
@Override |
|
||||||
protected void doInTransactionWithoutResult(TransactionStatus status) { |
|
||||||
assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); |
|
||||||
status.setRollbackOnly(); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true).flush(); |
|
||||||
return l; |
|
||||||
} |
|
||||||
}); |
|
||||||
assertTrue("Correct result list", result == l); |
|
||||||
|
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("Hasn't thread con", !TransactionSynchronizationManager.hasResource(ds)); |
|
||||||
verify(pm).flush(); |
|
||||||
verify(pm).close(); |
|
||||||
verify(con).setSavepoint(ConnectionHolder.SAVEPOINT_NAME_PREFIX + 1); |
|
||||||
verify(con).rollback(sp); |
|
||||||
verify(dialect).beginTransaction(tx, tt); |
|
||||||
verify(dialect).releaseJdbcConnection(conHandle, pm); |
|
||||||
verify(dialect).cleanupTransaction(null); |
|
||||||
verify(tx).commit(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testTransactionFlush() { |
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
given(pm.currentTransaction()).willReturn(tx); |
|
||||||
|
|
||||||
PlatformTransactionManager tm = new JdoTransactionManager(pmf); |
|
||||||
TransactionTemplate tt = new TransactionTemplate(tm); |
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); |
|
||||||
|
|
||||||
tt.execute(new TransactionCallbackWithoutResult() { |
|
||||||
@Override |
|
||||||
public void doInTransactionWithoutResult(TransactionStatus status) { |
|
||||||
assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
status.flush(); |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); |
|
||||||
verify(pm).flush(); |
|
||||||
verify(pm).close(); |
|
||||||
verify(tx).begin(); |
|
||||||
verify(tx).commit(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,159 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2013 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.Properties; |
|
||||||
import javax.jdo.JDOFatalUserException; |
|
||||||
import javax.jdo.PersistenceManagerFactory; |
|
||||||
|
|
||||||
import org.junit.Test; |
|
||||||
|
|
||||||
import org.springframework.core.io.ClassPathResource; |
|
||||||
|
|
||||||
import static org.junit.Assert.*; |
|
||||||
import static org.mockito.BDDMockito.*; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @author Phillip Webb |
|
||||||
*/ |
|
||||||
public class LocalPersistenceManagerFactoryTests { |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testLocalPersistenceManagerFactoryBean() throws IOException { |
|
||||||
final PersistenceManagerFactory pmf = mock(PersistenceManagerFactory.class); |
|
||||||
LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean() { |
|
||||||
@Override |
|
||||||
protected PersistenceManagerFactory newPersistenceManagerFactory(Map props) { |
|
||||||
return pmf; |
|
||||||
} |
|
||||||
}; |
|
||||||
pmfb.setJdoProperties(new Properties()); |
|
||||||
pmfb.afterPropertiesSet(); |
|
||||||
assertSame(pmf, pmfb.getObject()); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testLocalPersistenceManagerFactoryBeanWithInvalidSettings() throws IOException { |
|
||||||
LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean(); |
|
||||||
try { |
|
||||||
pmfb.afterPropertiesSet(); |
|
||||||
fail("Should have thrown JDOFatalUserException"); |
|
||||||
} |
|
||||||
catch (JDOFatalUserException ex) { |
|
||||||
// expected
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testLocalPersistenceManagerFactoryBeanWithIncompleteProperties() throws IOException { |
|
||||||
LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean(); |
|
||||||
Properties props = new Properties(); |
|
||||||
props.setProperty("myKey", "myValue"); |
|
||||||
pmfb.setJdoProperties(props); |
|
||||||
try { |
|
||||||
pmfb.afterPropertiesSet(); |
|
||||||
fail("Should have thrown JDOFatalUserException"); |
|
||||||
} |
|
||||||
catch (JDOFatalUserException ex) { |
|
||||||
// expected
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testLocalPersistenceManagerFactoryBeanWithInvalidProperty() throws IOException { |
|
||||||
LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean() { |
|
||||||
@Override |
|
||||||
protected PersistenceManagerFactory newPersistenceManagerFactory(Map props) { |
|
||||||
throw new IllegalArgumentException((String) props.get("myKey")); |
|
||||||
} |
|
||||||
}; |
|
||||||
Properties props = new Properties(); |
|
||||||
props.setProperty("myKey", "myValue"); |
|
||||||
pmfb.setJdoProperties(props); |
|
||||||
try { |
|
||||||
pmfb.afterPropertiesSet(); |
|
||||||
fail("Should have thrown IllegalArgumentException"); |
|
||||||
} |
|
||||||
catch (IllegalArgumentException ex) { |
|
||||||
// expected
|
|
||||||
assertTrue("Correct exception", "myValue".equals(ex.getMessage())); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testLocalPersistenceManagerFactoryBeanWithFile() throws IOException { |
|
||||||
LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean() { |
|
||||||
@Override |
|
||||||
protected PersistenceManagerFactory newPersistenceManagerFactory(Map props) { |
|
||||||
throw new IllegalArgumentException((String) props.get("myKey")); |
|
||||||
} |
|
||||||
}; |
|
||||||
pmfb.setConfigLocation(new ClassPathResource("test.properties", getClass())); |
|
||||||
try { |
|
||||||
pmfb.afterPropertiesSet(); |
|
||||||
fail("Should have thrown IllegalArgumentException"); |
|
||||||
} |
|
||||||
catch (IllegalArgumentException ex) { |
|
||||||
// expected
|
|
||||||
assertTrue("Correct exception", "myValue".equals(ex.getMessage())); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testLocalPersistenceManagerFactoryBeanWithName() throws IOException { |
|
||||||
LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean() { |
|
||||||
@Override |
|
||||||
protected PersistenceManagerFactory newPersistenceManagerFactory(String name) { |
|
||||||
throw new IllegalArgumentException(name); |
|
||||||
} |
|
||||||
}; |
|
||||||
pmfb.setPersistenceManagerFactoryName("myName"); |
|
||||||
try { |
|
||||||
pmfb.afterPropertiesSet(); |
|
||||||
fail("Should have thrown IllegalArgumentException"); |
|
||||||
} |
|
||||||
catch (IllegalArgumentException ex) { |
|
||||||
// expected
|
|
||||||
assertTrue("Correct exception", "myName".equals(ex.getMessage())); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testLocalPersistenceManagerFactoryBeanWithNameAndProperties() throws IOException { |
|
||||||
LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean() { |
|
||||||
@Override |
|
||||||
protected PersistenceManagerFactory newPersistenceManagerFactory(String name) { |
|
||||||
throw new IllegalArgumentException(name); |
|
||||||
} |
|
||||||
}; |
|
||||||
pmfb.setPersistenceManagerFactoryName("myName"); |
|
||||||
pmfb.getJdoPropertyMap().put("myKey", "myValue"); |
|
||||||
try { |
|
||||||
pmfb.afterPropertiesSet(); |
|
||||||
fail("Should have thrown IllegalStateException"); |
|
||||||
} |
|
||||||
catch (IllegalStateException ex) { |
|
||||||
// expected
|
|
||||||
assertTrue(ex.getMessage().indexOf("persistenceManagerFactoryName") != -1); |
|
||||||
assertTrue(ex.getMessage().indexOf("jdoProp") != -1); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,148 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2013 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.orm.jdo.support; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import javax.jdo.PersistenceManager; |
|
||||||
import javax.jdo.PersistenceManagerFactory; |
|
||||||
import javax.servlet.FilterChain; |
|
||||||
import javax.servlet.ServletException; |
|
||||||
import javax.servlet.ServletRequest; |
|
||||||
import javax.servlet.ServletResponse; |
|
||||||
|
|
||||||
import org.junit.Test; |
|
||||||
|
|
||||||
import org.springframework.mock.web.test.MockFilterConfig; |
|
||||||
import org.springframework.mock.web.test.MockHttpServletRequest; |
|
||||||
import org.springframework.mock.web.test.MockHttpServletResponse; |
|
||||||
import org.springframework.mock.web.test.MockServletContext; |
|
||||||
import org.springframework.mock.web.test.PassThroughFilterChain; |
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager; |
|
||||||
import org.springframework.web.context.WebApplicationContext; |
|
||||||
import org.springframework.web.context.request.ServletWebRequest; |
|
||||||
import org.springframework.web.context.support.StaticWebApplicationContext; |
|
||||||
|
|
||||||
import static org.junit.Assert.*; |
|
||||||
import static org.mockito.BDDMockito.*; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @author Chris Beams |
|
||||||
* @author Phillip Webb |
|
||||||
* @since 15.06.2004 |
|
||||||
*/ |
|
||||||
public class OpenPersistenceManagerInViewTests { |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testOpenPersistenceManagerInViewInterceptor() throws Exception { |
|
||||||
PersistenceManagerFactory pmf = mock(PersistenceManagerFactory.class); |
|
||||||
PersistenceManager pm = mock(PersistenceManager.class); |
|
||||||
|
|
||||||
OpenPersistenceManagerInViewInterceptor interceptor = new OpenPersistenceManagerInViewInterceptor(); |
|
||||||
interceptor.setPersistenceManagerFactory(pmf); |
|
||||||
|
|
||||||
MockServletContext sc = new MockServletContext(); |
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest(sc); |
|
||||||
|
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
interceptor.preHandle(new ServletWebRequest(request)); |
|
||||||
assertTrue(TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
|
|
||||||
// check that further invocations simply participate
|
|
||||||
interceptor.preHandle(new ServletWebRequest(request)); |
|
||||||
|
|
||||||
interceptor.preHandle(new ServletWebRequest(request)); |
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null); |
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null); |
|
||||||
|
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null); |
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null); |
|
||||||
|
|
||||||
interceptor.preHandle(new ServletWebRequest(request)); |
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null); |
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null); |
|
||||||
|
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null); |
|
||||||
assertTrue(TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
|
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null); |
|
||||||
assertFalse(TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testOpenPersistenceManagerInViewFilter() throws Exception { |
|
||||||
final PersistenceManagerFactory pmf = mock(PersistenceManagerFactory.class); |
|
||||||
PersistenceManager pm = mock(PersistenceManager.class); |
|
||||||
|
|
||||||
given(pmf.getPersistenceManager()).willReturn(pm); |
|
||||||
final PersistenceManagerFactory pmf2 = mock(PersistenceManagerFactory.class); |
|
||||||
PersistenceManager pm2 = mock(PersistenceManager.class); |
|
||||||
|
|
||||||
given(pmf2.getPersistenceManager()).willReturn(pm2); |
|
||||||
|
|
||||||
MockServletContext sc = new MockServletContext(); |
|
||||||
StaticWebApplicationContext wac = new StaticWebApplicationContext(); |
|
||||||
wac.setServletContext(sc); |
|
||||||
wac.getDefaultListableBeanFactory().registerSingleton("persistenceManagerFactory", pmf); |
|
||||||
wac.getDefaultListableBeanFactory().registerSingleton("myPersistenceManagerFactory", pmf2); |
|
||||||
wac.refresh(); |
|
||||||
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); |
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest(sc); |
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse(); |
|
||||||
|
|
||||||
MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter"); |
|
||||||
MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2"); |
|
||||||
filterConfig2.addInitParameter("persistenceManagerFactoryBeanName", "myPersistenceManagerFactory"); |
|
||||||
|
|
||||||
final OpenPersistenceManagerInViewFilter filter = new OpenPersistenceManagerInViewFilter(); |
|
||||||
filter.init(filterConfig); |
|
||||||
final OpenPersistenceManagerInViewFilter filter2 = new OpenPersistenceManagerInViewFilter(); |
|
||||||
filter2.init(filterConfig2); |
|
||||||
|
|
||||||
final FilterChain filterChain = new FilterChain() { |
|
||||||
@Override |
|
||||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) { |
|
||||||
assertTrue(TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
servletRequest.setAttribute("invoked", Boolean.TRUE); |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
final FilterChain filterChain2 = new FilterChain() { |
|
||||||
@Override |
|
||||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) |
|
||||||
throws IOException, ServletException { |
|
||||||
assertTrue(TransactionSynchronizationManager.hasResource(pmf2)); |
|
||||||
filter.doFilter(servletRequest, servletResponse, filterChain); |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
FilterChain filterChain3 = new PassThroughFilterChain(filter2, filterChain2); |
|
||||||
|
|
||||||
assertFalse(TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertFalse(TransactionSynchronizationManager.hasResource(pmf2)); |
|
||||||
filter2.doFilter(request, response, filterChain3); |
|
||||||
assertFalse(TransactionSynchronizationManager.hasResource(pmf)); |
|
||||||
assertFalse(TransactionSynchronizationManager.hasResource(pmf2)); |
|
||||||
assertNotNull(request.getAttribute("invoked")); |
|
||||||
|
|
||||||
verify(pm).close(); |
|
||||||
verify(pm2).close(); |
|
||||||
|
|
||||||
wac.close(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1 +0,0 @@ |
|||||||
myKey=myValue |
|
||||||
Loading…
Reference in new issue