/*
* Copyright 2002-2009 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.jpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.support.DataAccessUtils;
/**
* Base class for JpaTemplate and JpaInterceptor, defining common
* properties such as EntityManagerFactory and flushing behavior.
*
* <p>Not intended to be used directly.
* See {@link JpaTemplate} and {@link JpaInterceptor}.
*
* @author Juergen Hoeller
* @since 2.0
* @see #setEntityManagerFactory
* @see #setEntityManager
* @see #setJpaDialect
* @see #setFlushEager
* @see JpaTemplate
* @see JpaInterceptor
* @see JpaDialect
*/
public abstract class JpaAccessor extends EntityManagerFactoryAccessor implements InitializingBean {
private EntityManager entityManager;
private JpaDialect jpaDialect = new DefaultJpaDialect();
private boolean flushEager = false;
/**
* Set the JPA EntityManager to use.
*/
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
/**
* Return the JPA EntityManager to use.
*/
public EntityManager getEntityManager() {
return entityManager;
}
/**
* Set the JPA dialect to use for this accessor.
* <p>The dialect object can be used to retrieve the underlying JDBC
* connection, for example.
*/
public void setJpaDialect(JpaDialect jpaDialect) {
this.jpaDialect = (jpaDialect != null ? jpaDialect : new DefaultJpaDialect());
}
/**
* Return the JPA dialect to use for this accessor.
* <p>Creates a default one for the specified EntityManagerFactory if none set.
*/
public JpaDialect getJpaDialect() {
return this.jpaDialect;
}
/**
* Set if this accessor should flush changes to the database eagerly.
* <p>Eager flushing leads to immediate synchronization with the database,
* even if in a transaction. This causes inconsistencies to show up and throw
* a respective exception immediately, and JDBC access code that participates
* in the same transaction will see the changes as the database is already
* aware of them then. But the drawbacks are:
* <ul>
* <li>additional communication roundtrips with the database, instead of a
* single batch at transaction commit;
* <li>the fact that an actual database rollback is needed if the JPA
* transaction rolls back (due to already submitted SQL statements).
* </ul>
*/
public void setFlushEager(boolean flushEager) {
this.flushEager = flushEager;
}
/**
* Return if this accessor should flush changes to the database eagerly.
*/
public boolean isFlushEager() {
return this.flushEager;
}
/**
* Eagerly initialize the JPA dialect, creating a default one
* for the specified EntityManagerFactory if none set.
*/
public void afterPropertiesSet() {
EntityManagerFactory emf = getEntityManagerFactory();
if (emf == null && getEntityManager() == null) {
throw new IllegalArgumentException("'entityManagerFactory' or 'entityManager' is required");
}
if (emf instanceof EntityManagerFactoryInfo) {
JpaDialect jpaDialect = ((EntityManagerFactoryInfo) emf).getJpaDialect();
if (jpaDialect != null) {
setJpaDialect(jpaDialect);
}
}
}
/**
* Flush the given JPA entity manager if necessary.
* @param em the current JPA PersistenceManage
* @param existingTransaction if executing within an existing transaction
* @throws javax.persistence.PersistenceException in case of JPA flushing errors
*/
protected void flushIfNecessary(EntityManager em, boolean existingTransaction) throws PersistenceException {
if (isFlushEager()) {
logger.debug("Eagerly flushing JPA entity manager");
em.flush();
}
}
/**
* Convert the given runtime exception to an appropriate exception from the
* <code>org.springframework.dao</code> hierarchy if necessary, or
* return the exception itself if it is not persistence related
* <p>Default implementation delegates to the JpaDialect.
* May be overridden in subclasses.
* @param ex runtime exception that occured, which may or may not
* be JPA-related
* @return the corresponding DataAccessException instance if
* wrapping should occur, otherwise the raw exception
* @see org.springframework.dao.support.DataAccessUtils#translateIfNecessary
*/
public RuntimeException translateIfNecessary(RuntimeException ex) {
return DataAccessUtils.translateIfNecessary(ex, getJpaDialect());
}
}
|