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