30 changed files with 55 additions and 4358 deletions
@ -1,272 +0,0 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -1,5 +0,0 @@
|
||||
/** |
||||
* Classes supporting the {@code org.springframework.orm.jdo} package. |
||||
*/ |
||||
package org.springframework.orm.jdo.support; |
||||
|
||||
@ -1,7 +1,7 @@
@@ -1,7 +1,7 @@
|
||||
<html> |
||||
<body> |
||||
<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> |
||||
</body> |
||||
</html> |
||||
@ -1,796 +0,0 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -1 +0,0 @@
|
||||
myKey=myValue |
||||
Loading…
Reference in new issue