提交 d341624e 编写于 作者: J Juergen Hoeller

Drop JDO support

Issue: SPR-14130
上级 2b3445df
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -20,14 +20,12 @@ import java.sql.Connection;
/**
* Simple interface to be implemented by handles for a JDBC Connection.
* Used by JpaDialect and JdoDialect, for example.
* Used by JpaDialect, for example.
*
* @author Juergen Hoeller
* @since 1.1
* @see SimpleConnectionHandle
* @see ConnectionHolder
* @see org.springframework.orm.jdo.JpaDialect#getJdbcConnection
* @see org.springframework.orm.jdo.JdoDialect#getJdbcConnection
*/
public interface ConnectionHandle {
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -182,9 +182,7 @@ public class ConnectionHolder extends ResourceHolderSupport {
* <p>This is necessary for ConnectionHandles that expect "Connection borrowing",
* where each returned Connection is only temporarily leased and needs to be
* returned once the data operation is done, to make the Connection available
* for other operations within the same transaction. This is the case with
* JDO 2.0 DataStoreConnections, for example.
* @see org.springframework.orm.jdo.DefaultJdoDialect#getJdbcConnection
* for other operations within the same transaction.
*/
@Override
public void released() {
......
/*
* 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);
}
}
}
/*
* 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);
}
/*
* 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);
}
}
/*
* 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);
}
}
/*
* 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);
}
}
/*
* 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);
}
}
/*
* 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);
}
}
/*
* 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();
}
}
/*
* 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);
}
}
}
/*
* 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;
}
}
/*
* 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();
}
}
}
}
/**
* 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;
/*
* 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);
}
}
/*
* 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;
}
}
/*
* 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());
}
}
}
}
/*
* 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;
}
}
/**
* Classes supporting the {@code org.springframework.orm.jdo} package.
*/
package org.springframework.orm.jdo.support;
<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>
\ No newline at end of file
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.jdo;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import javax.jdo.JDOFatalUserException;
import javax.jdo.PersistenceManagerFactory;
import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
import static org.junit.Assert.*;
import static org.mockito.BDDMockito.*;
/**
* @author Juergen Hoeller
* @author Phillip Webb
*/
public class LocalPersistenceManagerFactoryTests {
@Test
public void testLocalPersistenceManagerFactoryBean() throws IOException {
final PersistenceManagerFactory pmf = mock(PersistenceManagerFactory.class);
LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean() {
@Override
protected PersistenceManagerFactory newPersistenceManagerFactory(Map props) {
return pmf;
}
};
pmfb.setJdoProperties(new Properties());
pmfb.afterPropertiesSet();
assertSame(pmf, pmfb.getObject());
}
@Test
public void testLocalPersistenceManagerFactoryBeanWithInvalidSettings() throws IOException {
LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean();
try {
pmfb.afterPropertiesSet();
fail("Should have thrown JDOFatalUserException");
}
catch (JDOFatalUserException ex) {
// expected
}
}
@Test
public void testLocalPersistenceManagerFactoryBeanWithIncompleteProperties() throws IOException {
LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean();
Properties props = new Properties();
props.setProperty("myKey", "myValue");
pmfb.setJdoProperties(props);
try {
pmfb.afterPropertiesSet();
fail("Should have thrown JDOFatalUserException");
}
catch (JDOFatalUserException ex) {
// expected
}
}
@Test
public void testLocalPersistenceManagerFactoryBeanWithInvalidProperty() throws IOException {
LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean() {
@Override
protected PersistenceManagerFactory newPersistenceManagerFactory(Map props) {
throw new IllegalArgumentException((String) props.get("myKey"));
}
};
Properties props = new Properties();
props.setProperty("myKey", "myValue");
pmfb.setJdoProperties(props);
try {
pmfb.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
// expected
assertTrue("Correct exception", "myValue".equals(ex.getMessage()));
}
}
@Test
public void testLocalPersistenceManagerFactoryBeanWithFile() throws IOException {
LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean() {
@Override
protected PersistenceManagerFactory newPersistenceManagerFactory(Map props) {
throw new IllegalArgumentException((String) props.get("myKey"));
}
};
pmfb.setConfigLocation(new ClassPathResource("test.properties", getClass()));
try {
pmfb.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
// expected
assertTrue("Correct exception", "myValue".equals(ex.getMessage()));
}
}
@Test
public void testLocalPersistenceManagerFactoryBeanWithName() throws IOException {
LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean() {
@Override
protected PersistenceManagerFactory newPersistenceManagerFactory(String name) {
throw new IllegalArgumentException(name);
}
};
pmfb.setPersistenceManagerFactoryName("myName");
try {
pmfb.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
// expected
assertTrue("Correct exception", "myName".equals(ex.getMessage()));
}
}
@Test
public void testLocalPersistenceManagerFactoryBeanWithNameAndProperties() throws IOException {
LocalPersistenceManagerFactoryBean pmfb = new LocalPersistenceManagerFactoryBean() {
@Override
protected PersistenceManagerFactory newPersistenceManagerFactory(String name) {
throw new IllegalArgumentException(name);
}
};
pmfb.setPersistenceManagerFactoryName("myName");
pmfb.getJdoPropertyMap().put("myKey", "myValue");
try {
pmfb.afterPropertiesSet();
fail("Should have thrown IllegalStateException");
}
catch (IllegalStateException ex) {
// expected
assertTrue(ex.getMessage().indexOf("persistenceManagerFactoryName") != -1);
assertTrue(ex.getMessage().indexOf("jdoProp") != -1);
}
}
}
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.jdo.support;
import java.io.IOException;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.junit.Test;
import org.springframework.mock.web.test.MockFilterConfig;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse;
import org.springframework.mock.web.test.MockServletContext;
import org.springframework.mock.web.test.PassThroughFilterChain;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.support.StaticWebApplicationContext;
import static org.junit.Assert.*;
import static org.mockito.BDDMockito.*;
/**
* @author Juergen Hoeller
* @author Chris Beams
* @author Phillip Webb
* @since 15.06.2004
*/
public class OpenPersistenceManagerInViewTests {
@Test
public void testOpenPersistenceManagerInViewInterceptor() throws Exception {
PersistenceManagerFactory pmf = mock(PersistenceManagerFactory.class);
PersistenceManager pm = mock(PersistenceManager.class);
OpenPersistenceManagerInViewInterceptor interceptor = new OpenPersistenceManagerInViewInterceptor();
interceptor.setPersistenceManagerFactory(pmf);
MockServletContext sc = new MockServletContext();
MockHttpServletRequest request = new MockHttpServletRequest(sc);
given(pmf.getPersistenceManager()).willReturn(pm);
interceptor.preHandle(new ServletWebRequest(request));
assertTrue(TransactionSynchronizationManager.hasResource(pmf));
// check that further invocations simply participate
interceptor.preHandle(new ServletWebRequest(request));
interceptor.preHandle(new ServletWebRequest(request));
interceptor.postHandle(new ServletWebRequest(request), null);
interceptor.afterCompletion(new ServletWebRequest(request), null);
interceptor.postHandle(new ServletWebRequest(request), null);
interceptor.afterCompletion(new ServletWebRequest(request), null);
interceptor.preHandle(new ServletWebRequest(request));
interceptor.postHandle(new ServletWebRequest(request), null);
interceptor.afterCompletion(new ServletWebRequest(request), null);
interceptor.postHandle(new ServletWebRequest(request), null);
assertTrue(TransactionSynchronizationManager.hasResource(pmf));
interceptor.afterCompletion(new ServletWebRequest(request), null);
assertFalse(TransactionSynchronizationManager.hasResource(pmf));
}
@Test
public void testOpenPersistenceManagerInViewFilter() throws Exception {
final PersistenceManagerFactory pmf = mock(PersistenceManagerFactory.class);
PersistenceManager pm = mock(PersistenceManager.class);
given(pmf.getPersistenceManager()).willReturn(pm);
final PersistenceManagerFactory pmf2 = mock(PersistenceManagerFactory.class);
PersistenceManager pm2 = mock(PersistenceManager.class);
given(pmf2.getPersistenceManager()).willReturn(pm2);
MockServletContext sc = new MockServletContext();
StaticWebApplicationContext wac = new StaticWebApplicationContext();
wac.setServletContext(sc);
wac.getDefaultListableBeanFactory().registerSingleton("persistenceManagerFactory", pmf);
wac.getDefaultListableBeanFactory().registerSingleton("myPersistenceManagerFactory", pmf2);
wac.refresh();
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
MockHttpServletRequest request = new MockHttpServletRequest(sc);
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2");
filterConfig2.addInitParameter("persistenceManagerFactoryBeanName", "myPersistenceManagerFactory");
final OpenPersistenceManagerInViewFilter filter = new OpenPersistenceManagerInViewFilter();
filter.init(filterConfig);
final OpenPersistenceManagerInViewFilter filter2 = new OpenPersistenceManagerInViewFilter();
filter2.init(filterConfig2);
final FilterChain filterChain = new FilterChain() {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) {
assertTrue(TransactionSynchronizationManager.hasResource(pmf));
servletRequest.setAttribute("invoked", Boolean.TRUE);
}
};
final FilterChain filterChain2 = new FilterChain() {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse)
throws IOException, ServletException {
assertTrue(TransactionSynchronizationManager.hasResource(pmf2));
filter.doFilter(servletRequest, servletResponse, filterChain);
}
};
FilterChain filterChain3 = new PassThroughFilterChain(filter2, filterChain2);
assertFalse(TransactionSynchronizationManager.hasResource(pmf));
assertFalse(TransactionSynchronizationManager.hasResource(pmf2));
filter2.doFilter(request, response, filterChain3);
assertFalse(TransactionSynchronizationManager.hasResource(pmf));
assertFalse(TransactionSynchronizationManager.hasResource(pmf2));
assertNotNull(request.getAttribute("invoked"));
verify(pm).close();
verify(pm2).close();
wac.close();
}
}
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -20,7 +20,7 @@ import org.springframework.dao.DataAccessException;
/**
* Interface implemented by Spring integrations with data access technologies
* that throw runtime exceptions, such as JPA, TopLink, JDO and Hibernate.
* that throw runtime exceptions, such as JPA and Hibernate.
*
* <p>This allows consistent usage of combined exception translation functionality,
* without forcing a single translator to understand every single possible type
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -83,8 +83,8 @@ public class LocalConnectionFactoryBean implements FactoryBean<Object>, Initiali
* <p>The ManagerConnectionFactory will usually be set up as separate bean
* (potentially as inner bean), populated with JavaBean properties:
* a ManagerConnectionFactory is encouraged to follow the JavaBean pattern
* by the JCA specification, analogous to a JDBC DataSource and a JDO
* PersistenceManagerFactory.
* by the JCA specification, analogous to a JDBC DataSource and a JPA
* EntityManagerFactory.
* <p>Note that the ManagerConnectionFactory implementation might expect
* a reference to its JCA 1.5 ResourceAdapter, expressed through the
* {@link javax.resource.spi.ResourceAdapterAssociation} interface.
......
......@@ -1726,7 +1726,7 @@ proxies for beans containing that annotation:
The `TransactionInterceptor` defined here depends on a `PlatformTransactionManager`
definition, which is not included in this generic file (although it could be) because it
will be specific to the application's transaction requirements (typically JTA, as in
this example, or Hibernate, JDO or JDBC):
this example, or Hibernate or JDBC):
[source,xml,indent=0]
[subs="verbatim,quotes"]
......
......@@ -1450,7 +1450,7 @@ proxies for beans containing that annotation:
The `TransactionInterceptor` defined here depends on a `PlatformTransactionManager`
definition, which is not included in this generic file (although it could be) because it
will be specific to the application's transaction requirements (typically JTA, as in
this example, or Hibernate, JDO or JDBC):
this example, or Hibernate or JDBC):
[source,xml,indent=0]
[subs="verbatim,quotes"]
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册