Drop JDO support

Issue: SPR-14130
This commit is contained in:
Juergen Hoeller 2016-07-04 23:34:48 +02:00
parent 2b3445df81
commit d341624e91
30 changed files with 55 additions and 4358 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,14 +20,12 @@ import java.sql.Connection;
/**
* Simple interface to be implemented by handles for a JDBC Connection.
* Used by JpaDialect and JdoDialect, for example.
* Used by JpaDialect, for example.
*
* @author Juergen Hoeller
* @since 1.1
* @see SimpleConnectionHandle
* @see ConnectionHolder
* @see org.springframework.orm.jdo.JpaDialect#getJdbcConnection
* @see org.springframework.orm.jdo.JdoDialect#getJdbcConnection
*/
public interface ConnectionHandle {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -182,9 +182,7 @@ public class ConnectionHolder extends ResourceHolderSupport {
* <p>This is necessary for ConnectionHandles that expect "Connection borrowing",
* where each returned Connection is only temporarily leased and needs to be
* returned once the data operation is done, to make the Connection available
* for other operations within the same transaction. This is the case with
* JDO 2.0 DataStoreConnections, for example.
* @see org.springframework.orm.jdo.DefaultJdoDialect#getJdbcConnection
* for other operations within the same transaction.
*/
@Override
public void released() {

View File

@ -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);
}
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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">
* &lt;bean id="persistenceManagerFactory" class="org.jpox.PersistenceManagerFactoryImpl" destroy-method="close"&gt;
* &lt;property name="connectionFactory" ref="dataSource"/&gt;
* &lt;property name="nontransactionalRead" value="true"/&gt;
* &lt;/bean&gt;
* </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();
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}
}
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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());
}
}
}
}

View File

@ -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;
}
}

View File

@ -1,5 +0,0 @@
/**
* Classes supporting the {@code org.springframework.orm.jdo} package.
*/
package org.springframework.orm.jdo.support;

View File

@ -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>

View File

@ -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();
}
}

View File

@ -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);
}
}
}

View File

@ -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();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,7 +20,7 @@ import org.springframework.dao.DataAccessException;
/**
* Interface implemented by Spring integrations with data access technologies
* that throw runtime exceptions, such as JPA, TopLink, JDO and Hibernate.
* that throw runtime exceptions, such as JPA and Hibernate.
*
* <p>This allows consistent usage of combined exception translation functionality,
* without forcing a single translator to understand every single possible type

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -83,8 +83,8 @@ public class LocalConnectionFactoryBean implements FactoryBean<Object>, Initiali
* <p>The ManagerConnectionFactory will usually be set up as separate bean
* (potentially as inner bean), populated with JavaBean properties:
* a ManagerConnectionFactory is encouraged to follow the JavaBean pattern
* by the JCA specification, analogous to a JDBC DataSource and a JDO
* PersistenceManagerFactory.
* by the JCA specification, analogous to a JDBC DataSource and a JPA
* EntityManagerFactory.
* <p>Note that the ManagerConnectionFactory implementation might expect
* a reference to its JCA 1.5 ResourceAdapter, expressed through the
* {@link javax.resource.spi.ResourceAdapterAssociation} interface.

View File

@ -1726,7 +1726,7 @@ proxies for beans containing that annotation:
The `TransactionInterceptor` defined here depends on a `PlatformTransactionManager`
definition, which is not included in this generic file (although it could be) because it
will be specific to the application's transaction requirements (typically JTA, as in
this example, or Hibernate, JDO or JDBC):
this example, or Hibernate or JDBC):
[source,xml,indent=0]
[subs="verbatim,quotes"]

View File

@ -1450,7 +1450,7 @@ proxies for beans containing that annotation:
The `TransactionInterceptor` defined here depends on a `PlatformTransactionManager`
definition, which is not included in this generic file (although it could be) because it
will be specific to the application's transaction requirements (typically JTA, as in
this example, or Hibernate, JDO or JDBC):
this example, or Hibernate or JDBC):
[source,xml,indent=0]
[subs="verbatim,quotes"]

View File

@ -29,8 +29,7 @@ Framework. The Spring Framework provides a consistent abstraction for transactio
management that delivers the following benefits:
* Consistent programming model across different transaction APIs such as Java
Transaction API (JTA), JDBC, Hibernate, Java Persistence API (JPA), and Java Data
Objects (JDO).
Transaction API (JTA), JDBC, Hibernate, and Java Persistence API (JPA).
* Support for <<transaction-declarative,declarative transaction management>>.
* Simpler API for <<transaction-programmatic,programmatic>> transaction management than
complex transaction APIs such as JTA.
@ -384,7 +383,7 @@ It should now be clear how you create different transaction managers, and how th
linked to related resources that need to be synchronized to transactions (for example
`DataSourceTransactionManager` to a JDBC `DataSource`, `HibernateTransactionManager` to
a Hibernate `SessionFactory`, and so forth). This section describes how the application
code, directly or indirectly using a persistence API such as JDBC, Hibernate, or JDO,
code, directly or indirectly using a persistence API such as JDBC, Hibernate, or JPA,
ensures that these resources are created, reused, and cleaned up properly. The section
also discusses how transaction synchronization is triggered (optionally) through the
relevant `PlatformTransactionManager`.
@ -408,12 +407,11 @@ chapters of this reference documentation.
[[tx-resource-synchronization-low]]
==== Low-level synchronization approach
Classes such as `DataSourceUtils` (for JDBC), `EntityManagerFactoryUtils` (for JPA),
`SessionFactoryUtils` (for Hibernate), `PersistenceManagerFactoryUtils` (for JDO), and
so on exist at a lower level. When you want the application code to deal directly with
the resource types of the native persistence APIs, you use these classes to ensure that
proper Spring Framework-managed instances are obtained, transactions are (optionally)
synchronized, and exceptions that occur in the process are properly mapped to a
consistent API.
`SessionFactoryUtils` (for Hibernate), and so on exist at a lower level. When you want the
application code to deal directly with the resource types of the native persistence APIs,
you use these classes to ensure that proper Spring Framework-managed instances are obtained,
transactions are (optionally) synchronized, and exceptions that occur in the process are
properly mapped to a consistent API.
For example, in the case of JDBC, instead of the traditional JDBC approach of calling
the `getConnection()` method on the `DataSource`, you instead use Spring's
@ -485,7 +483,7 @@ necessary. The differences between the two types of transaction management are:
* Unlike EJB CMT, which is tied to JTA, the Spring Framework's declarative transaction
management works in any environment. It can work with JTA transactions or local
transactions using JDBC, JPA, Hibernate or JDO by simply adjusting the configuration
transactions using JDBC, JPA or Hibernate by simply adjusting the configuration
files.
* You can apply the Spring Framework declarative transaction management to any class,
not merely special classes such as EJBs.
@ -2058,7 +2056,7 @@ For more information about the Spring Framework's transaction support:
[[dao-introduction]]
=== Introduction
The Data Access Object (DAO) support in Spring is aimed at making it easy to work with
data access technologies like JDBC, Hibernate, JPA or JDO in a consistent way. This
data access technologies like JDBC, Hibernate or JPA in a consistent way. This
allows one to switch between the aforementioned persistence technologies fairly easily
and it also allows one to code without worrying about catching exceptions that are
specific to each technology.
@ -2074,8 +2072,8 @@ the root exception. These exceptions wrap the original exception so there is nev
risk that one might lose any information as to what might have gone wrong.
In addition to JDBC exceptions, Spring can also wrap Hibernate-specific exceptions,
converting them to a set of focused runtime exceptions (the same is true for JDO and
JPA exceptions). This allows one to handle most persistence exceptions, which are
converting them to a set of focused runtime exceptions (the same is true for JPA
exceptions). This allows one to handle most persistence exceptions, which are
non-recoverable, only in the appropriate layers, without having annoying boilerplate
catch-and-throw blocks and exception declarations in one's DAOs. (One can still trap
and handle exceptions anywhere one needs to though.) As mentioned above, JDBC
@ -2085,12 +2083,12 @@ programming model.
The above holds true for the various template classes in Springs support for various ORM
frameworks. If one uses the interceptor-based classes then the application must care
about handling `HibernateExceptions` and `JDOExceptions` itself, preferably via
about handling `HibernateExceptions` and `PersistenceExceptions` itself, preferably via
delegating to `SessionFactoryUtils`' `convertHibernateAccessException(..)` or
`convertJdoAccessException()` methods respectively. These methods convert the exceptions
`convertJpaAccessException()` methods respectively. These methods convert the exceptions
to ones that are compatible with the exceptions in the `org.springframework.dao`
exception hierarchy. As `JDOExceptions` are unchecked, they can simply get thrown too,
sacrificing generic DAO abstraction in terms of exceptions though.
exception hierarchy. As `PersistenceExceptions` are unchecked, they can simply get
thrown too, sacrificing generic DAO abstraction in terms of exceptions though.
The exception hierarchy that Spring provides can be seen below. (Please note that the
class hierarchy detailed in the image shows only a subset of the entire
@ -4952,17 +4950,17 @@ The second option can also be easy. Some suggestions on how to implement this in
[[orm-introduction]]
=== Introduction to ORM with Spring
The Spring Framework supports integration with Hibernate, Java Persistence API (JPA)
and Java Data Objects (JDO) for resource management, data access object
(DAO) implementations, and transaction strategies. For example, for Hibernate there is
first-class support with several convenient IoC features that address many typical
Hibernate integration issues. You can configure all of the supported features for O/R
(object relational) mapping tools through Dependency Injection. They can participate in
Spring's resource and transaction management, and they comply with Spring's generic
transaction and DAO exception hierarchies. The recommended integration style is to code
DAOs against plain Hibernate, JPA, and JDO APIs. The older style of using Spring's DAO
templates is no longer recommended; however, coverage of this style can be found in the
<<classic-spring-orm>> in the appendices.
The Spring Framework supports integration with the Java Persistence API (JPA) as well
as native Hibernate for resource management, data access object (DAO) implementations,
and transaction strategies. For example, for Hibernate there is first-class support with
several convenient IoC features that address many typical Hibernate integration issues.
You can configure all of the supported features for O/R (object relational) mapping
tools through Dependency Injection. They can participate in Spring's resource and
transaction management, and they comply with Spring's generic transaction and DAO
exception hierarchies. The recommended integration style is to code DAOs against plain
Hibernate or JPA APIs. The older style of using Spring's DAO templates is no longer
recommended; however, coverage of this style can be found in the <<classic-spring-orm>>
in the appendices.
Spring adds significant enhancements to the ORM layer of your choice when you create
data access applications. You can leverage as much of the integration support as you
@ -5061,26 +5059,25 @@ translation benefits.
When it comes to transaction management, the `JdbcTemplate` class hooks in to the Spring
transaction support and supports both JTA and JDBC transactions, through respective
Spring transaction managers. For the supported ORM technologies Spring offers Hibernate,
JPA and JDO support through the Hibernate, JPA, and JDO transaction managers as well as
JTA support. For details on transaction support, see the <<transaction>> chapter.
Spring transaction managers. For the supported ORM technologies Spring offers Hibernate
and JPA support through the Hibernate and JPA transaction managers as well as JTA support.
For details on transaction support, see the <<transaction>> chapter.
[[orm-exception-translation]]
==== Exception translation
When you use Hibernate, JPA, or JDO in a DAO, you must decide how to handle the
persistence technology's native exception classes. The DAO throws a subclass of a
`HibernateException`, `PersistenceException` or `JDOException` depending on the
technology. These exceptions are all run-time exceptions and do not have to be declared
or caught. You may also have to deal with `IllegalArgumentException` and
`IllegalStateException`. This means that callers can only treat exceptions as generally
fatal, unless they want to depend on the persistence technology's own exception
structure. Catching specific causes such as an optimistic locking failure is not
possible without tying the caller to the implementation strategy. This trade off might
be acceptable to applications that are strongly ORM-based and/or do not need any special
exception treatment. However, Spring enables exception translation to be applied
transparently through the `@Repository` annotation:
When you use Hibernate or JPA in a DAO, you must decide how to handle the persistence
technology's native exception classes. The DAO throws a subclass of a `HibernateException`
or `PersistenceException` depending on the technology. These exceptions are all runtime
exceptions and do not have to be declared or caught. You may also have to deal with
`IllegalArgumentException` and `IllegalStateException`. This means that callers can only
treat exceptions as generally fatal, unless they want to depend on the persistence
technology's own exception structure. Catching specific causes such as an optimistic
locking failure is not possible without tying the caller to the implementation strategy.
This trade-off might be acceptable to applications that are strongly ORM-based and/or
do not need any special exception treatment. However, Spring enables exception
translation to be applied transparently through the `@Repository` annotation:
[source,java,indent=0]
[subs="verbatim,quotes"]
@ -5718,305 +5715,12 @@ following events occur when a JTA transaction commits:
[[orm-jdo]]
=== JDO
Spring supports the standard JDO 2.0 and 2.1 APIs as data access strategy, following the
same style as the Hibernate support. The corresponding integration classes reside in the
`org.springframework.orm.jdo` package.
[[orm-jdo-setup]]
==== PersistenceManagerFactory setup
Spring provides a `LocalPersistenceManagerFactoryBean` class that allows you to define a
local JDO `PersistenceManagerFactory` within a Spring application context:
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<beans>
<bean id="myPmf" class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean">
<property name="configLocation" value="classpath:kodo.properties"/>
</bean>
</beans>
----
Alternatively, you can set up a `PersistenceManagerFactory` through direct instantiation
of a `PersistenceManagerFactory` implementation class. A JDO `PersistenceManagerFactory`
implementation class follows the JavaBeans pattern, just like a JDBC `DataSource`
implementation class, which is a natural fit for a configuration that uses Spring. This
setup style usually supports a Spring-defined JDBC `DataSource`, passed into the
`connectionFactory` property. For example, for the open source JDO implementation
DataNucleus (formerly JPOX) ( http://www.datanucleus.org/[http://www.datanucleus.org/]),
this is the XML configuration of the `PersistenceManagerFactory` implementation:
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<beans>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="myPmf" class="org.datanucleus.jdo.JDOPersistenceManagerFactory" destroy-method="close">
<property name="connectionFactory" ref="dataSource"/>
<property name="nontransactionalRead" value="true"/>
</bean>
</beans>
----
You can also set up JDO `PersistenceManagerFactory` in the JNDI environment of a Java EE
application server, usually through the JCA connector provided by the particular JDO
implementation. Spring's standard `JndiObjectFactoryBean` or `<jee:jndi-lookup>` can be
used to retrieve and expose such a `PersistenceManagerFactory`. However, outside an EJB
context, no real benefit exists in holding the `PersistenceManagerFactory` in JNDI: only
choose such a setup for a good reason. See <<orm-hibernate-resources>> for a discussion;
the arguments there apply to JDO as well.
[[orm-jdo-daos-straight]]
==== Implementing DAOs based on the plain JDO API
DAOs can also be written directly against plain JDO API, without any Spring
dependencies, by using an injected `PersistenceManagerFactory`. The following is an
example of a corresponding DAO implementation:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
public class ProductDaoImpl implements ProductDao {
private PersistenceManagerFactory persistenceManagerFactory;
public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
this.persistenceManagerFactory = pmf;
}
public Collection loadProductsByCategory(String category) {
PersistenceManager pm = this.persistenceManagerFactory.getPersistenceManager();
try {
Query query = pm.newQuery(Product.class, "category = pCategory");
query.declareParameters("String pCategory");
return query.execute(category);
}
finally {
pm.close();
}
}
}
----
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<beans>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="persistenceManagerFactory" ref="myPmf"/>
</bean>
</beans>
----
The main problem with such DAOs is that they always get a new `PersistenceManager` from
the factory. To access a Spring-managed transactional `PersistenceManager`, define a
`TransactionAwarePersistenceManagerFactoryProxy` (as included in Spring) in front of
your target `PersistenceManagerFactory`, then passing a reference to that proxy into
your DAOs as in the following example:
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<beans>
<bean id="myPmfProxy"
class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy">
<property name="targetPersistenceManagerFactory" ref="myPmf"/>
</bean>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="persistenceManagerFactory" ref="myPmfProxy"/>
</bean>
</beans>
----
Your data access code will receive a transactional `PersistenceManager` (if any) from
the `PersistenceManagerFactory.getPersistenceManager()` method that it calls. The latter
method call goes through the proxy, which first checks for a current transactional
`PersistenceManager` before getting a new one from the factory. Any `close()` calls on
the `PersistenceManager` are ignored in case of a transactional `PersistenceManager`.
If your data access code always runs within an active transaction (or at least within
active transaction synchronization), it is safe to omit the `PersistenceManager.close()`
call and thus the entire `finally` block, which you might do to keep your DAO
implementations concise:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
public class ProductDaoImpl implements ProductDao {
private PersistenceManagerFactory persistenceManagerFactory;
public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
this.persistenceManagerFactory = pmf;
}
public Collection loadProductsByCategory(String category) {
PersistenceManager pm = this.persistenceManagerFactory.getPersistenceManager();
Query query = pm.newQuery(Product.class, "category = pCategory");
query.declareParameters("String pCategory");
return query.execute(category);
}
}
----
With such DAOs that rely on active transactions, it is recommended that you enforce
active transactions through turning off
`TransactionAwarePersistenceManagerFactoryProxy`'s `allowCreate` flag:
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<beans>
<bean id="myPmfProxy"
class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy">
<property name="targetPersistenceManagerFactory" ref="myPmf"/>
<property name="allowCreate" value="false"/>
</bean>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="persistenceManagerFactory" ref="myPmfProxy"/>
</bean>
</beans>
----
The main advantage of this DAO style is that it depends on JDO API only; no import of
any Spring class is required. This is of course appealing from a non-invasiveness
perspective, and might feel more natural to JDO developers.
However, the DAO throws plain `JDOException` (which is unchecked, so does not have to be
declared or caught), which means that callers can only treat exceptions as fatal, unless
you want to depend on JDO's own exception structure. Catching specific causes such as an
optimistic locking failure is not possible without tying the caller to the
implementation strategy. This trade off might be acceptable to applications that are
strongly JDO-based and/or do not need any special exception treatment.
In summary, you can DAOs based on the plain JDO API, and they can still participate in
Spring-managed transactions. This strategy might appeal to you if you are already
familiar with JDO. However, such DAOs throw plain `JDOException`, and you would have to
convert explicitly to Spring's `DataAccessException` (if desired).
[[orm-jdo-tx]]
==== Transaction management
[NOTE]
====
You are __strongly__ encouraged to read <<transaction-declarative>> if you have not done
so, to get a more detailed coverage of Spring's declarative transaction support.
====
To execute service operations within transactions, you can use Spring's common
declarative transaction facilities. For example:
[source,xml,indent=0]
[subs="verbatim"]
----
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="myTxManager" class="org.springframework.orm.jdo.JdoTransactionManager">
<property name="persistenceManagerFactory" ref="myPmf"/>
</bean>
<bean id="myProductService" class="product.ProductServiceImpl">
<property name="productDao" ref="myProductDao"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="increasePrice*" propagation="REQUIRED"/>
<tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/>
<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="productServiceMethods"
expression="execution(* product.ProductService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/>
</aop:config>
</beans>
----
JDO requires an active transaction to modify a persistent object. The non-transactional
flush concept does not exist in JDO, in contrast to Hibernate. For this reason, you need
to set up the chosen JDO implementation for a specific environment. Specifically, you
need to set it up explicitly for JTA synchronization, to detect an active JTA
transaction itself. This is not necessary for local transactions as performed by
Spring's `JdoTransactionManager`, but it is necessary to participate in JTA
transactions, whether driven by Spring's `JtaTransactionManager` or by EJB CMT and plain
JTA.
`JdoTransactionManager` is capable of exposing a JDO transaction to JDBC access code
that accesses the same JDBC `DataSource`, provided that the registered `JdoDialect`
supports retrieval of the underlying JDBC `Connection`. This is the case for JDBC-based
JDO 2.0 implementations by default.
[[orm-jdo-dialect]]
==== JdoDialect
As an advanced feature, both `LocalPersistenceManagerFactoryBean` and `JdoTransactionManager`
support a custom `JdoDialect` that can be passed into the `jdoDialect` bean property.
Using a `JdoDialect` implementation, you can enable advanced features supported by Spring,
usually in a vendor-specific manner:
* Applying specific transaction semantics such as custom isolation level or transaction
timeout
* Retrieving the transactional JDBC `Connection` for exposure to JDBC-based DAOs
* Applying query timeouts, which are automatically calculated from Spring-managed
transaction timeouts
* Eagerly flushing a `PersistenceManager,` to make transactional changes visible to
JDBC-based data access code
* Advanced translation of `JDOExceptions` to Spring `DataAccessExceptions`
See the `JdoDialect` javadocs for more details on its operations and how to use them
within Spring's JDO support.
[[orm-jpa]]
=== JPA
The Spring JPA, available under the `org.springframework.orm.jpa` package, offers
comprehensive support for the
http://www.oracle.com/technetwork/articles/javaee/jpa-137156.html[Java Persistence
API] in a similar manner to the integration with Hibernate or JDO, while being aware of
API] in a similar manner to the integration with Hibernate, while being aware of
the underlying implementation in order to provide additional features.
@ -6472,7 +6176,7 @@ declarative transaction facilities. For example:
Spring JPA allows a configured `JpaTransactionManager` to expose a JPA transaction to
JDBC access code that accesses the same JDBC `DataSource`, provided that the registered
`JpaDialect` supports retrieval of the underlying JDBC `Connection`. Out of the box,
Spring provides dialects for the EclipseLink, Hibernate and OpenJPA JPA implementations.
Spring provides dialects for the EclipseLink and Hibernate JPA implementations.
See the next section for details on the `JpaDialect` mechanism.
@ -7007,74 +6711,9 @@ Available attributes are:
[[oxm-xmlbeans]]
=== XMLBeans
XMLBeans is an XML binding tool that has full XML Schema support, and offers full XML
Infoset fidelity. It takes a different approach to that of most other O/X mapping
frameworks, in that all classes that are generated from an XML Schema are all derived
from `XmlObject`, and contain XML binding information in them.
For more information on XMLBeans, refer to the http://xmlbeans.apache.org/[__XMLBeans
web site __]. The Spring-WS integration classes reside in the
`org.springframework.oxm.xmlbeans` package.
[[oxm-xmlbeans-marshaller]]
==== XmlBeansMarshaller
The `XmlBeansMarshaller` implements both the `Marshaller` and `Unmarshaller` interfaces.
It can be configured as follows:
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<beans>
<bean id="xmlBeansMarshaller" class="org.springframework.oxm.xmlbeans.XmlBeansMarshaller" />
...
</beans>
----
[NOTE]
====
Note that the `XmlBeansMarshaller` can only marshal objects of type `XmlObject`, and not
every `java.lang.Object`.
====
[[oxm-xmlbeans-xsd]]
===== XML Schema-based Configuration
The `xmlbeans-marshaller` tag configures a
`org.springframework.oxm.xmlbeans.XmlBeansMarshaller`. Here is an example:
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<oxm:xmlbeans-marshaller id="marshaller"/>
----
Available attributes are:
|===
| Attribute| Description| Required
| `id`
| the id of the marshaller
| no
| `options`
| the bean name of the XmlOptions that is to be used for this marshaller. Typically a
`XmlOptionsFactoryBean` definition
| no
|===
[[oxm-jibx]]
=== JiBX
The JiBX framework offers a solution similar to that which JDO provides for ORM: a
The JiBX framework offers a solution similar to that which Hibernate provides for ORM: a
binding definition defines the rules for how your Java objects are converted to or from
XML. After preparing the binding and compiling the classes, a JiBX binding compiler
enhances the class files, and adds code to handle converting instances of the classes