1 /*
2 * Copyright 2002-2007 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.springframework.orm.jpa;
18
19 import javax.persistence.EntityManager;
20 import javax.persistence.EntityManagerFactory;
21 import javax.persistence.PersistenceException;
22
23 import org.springframework.beans.factory.InitializingBean;
24 import org.springframework.dao.support.DataAccessUtils;
25
26 /**
27 * Base class for JpaTemplate and JpaInterceptor, defining common
28 * properties such as EntityManagerFactory and flushing behavior.
29 *
30 * <p>Not intended to be used directly.
31 * See {@link JpaTemplate} and {@link JpaInterceptor}.
32 *
33 * @author Juergen Hoeller
34 * @since 2.0
35 * @see #setEntityManagerFactory
36 * @see #setEntityManager
37 * @see #setJpaDialect
38 * @see #setFlushEager
39 * @see JpaTemplate
40 * @see JpaInterceptor
41 * @see JpaDialect
42 */
43 public abstract class JpaAccessor extends EntityManagerFactoryAccessor implements InitializingBean {
44
45 private EntityManager entityManager;
46
47 private JpaDialect jpaDialect = new DefaultJpaDialect();
48
49 private boolean flushEager = false;
50
51
52 /**
53 * Set the JPA EntityManager to use.
54 */
55 public void setEntityManager(EntityManager entityManager) {
56 this.entityManager = entityManager;
57 }
58
59 /**
60 * Return the JPA EntityManager to use.
61 */
62 public EntityManager getEntityManager() {
63 return entityManager;
64 }
65
66 /**
67 * Set the JPA dialect to use for this accessor.
68 * <p>The dialect object can be used to retrieve the underlying JDBC
69 * connection, for example.
70 */
71 public void setJpaDialect(JpaDialect jpaDialect) {
72 this.jpaDialect = (jpaDialect != null ? jpaDialect : new DefaultJpaDialect());
73 }
74
75 /**
76 * Return the JPA dialect to use for this accessor.
77 * <p>Creates a default one for the specified EntityManagerFactory if none set.
78 */
79 public JpaDialect getJpaDialect() {
80 return this.jpaDialect;
81 }
82
83 /**
84 * Set if this accessor should flush changes to the database eagerly.
85 * <p>Eager flushing leads to immediate synchronization with the database,
86 * even if in a transaction. This causes inconsistencies to show up and throw
87 * a respective exception immediately, and JDBC access code that participates
88 * in the same transaction will see the changes as the database is already
89 * aware of them then. But the drawbacks are:
90 * <ul>
91 * <li>additional communication roundtrips with the database, instead of a
92 * single batch at transaction commit;
93 * <li>the fact that an actual database rollback is needed if the JPA
94 * transaction rolls back (due to already submitted SQL statements).
95 * </ul>
96 */
97 public void setFlushEager(boolean flushEager) {
98 this.flushEager = flushEager;
99 }
100
101 /**
102 * Return if this accessor should flush changes to the database eagerly.
103 */
104 public boolean isFlushEager() {
105 return this.flushEager;
106 }
107
108 /**
109 * Eagerly initialize the JPA dialect, creating a default one
110 * for the specified EntityManagerFactory if none set.
111 */
112 public void afterPropertiesSet() {
113 EntityManagerFactory emf = getEntityManagerFactory();
114 if (emf == null && getEntityManager() == null) {
115 throw new IllegalArgumentException("entityManagerFactory or entityManager is required");
116 }
117 if (emf instanceof EntityManagerFactoryInfo) {
118 JpaDialect jpaDialect = ((EntityManagerFactoryInfo) emf).getJpaDialect();
119 if (jpaDialect != null) {
120 setJpaDialect(jpaDialect);
121 }
122 }
123 }
124
125
126 /**
127 * Flush the given JPA entity manager if necessary.
128 * @param em the current JPA PersistenceManage
129 * @param existingTransaction if executing within an existing transaction
130 * @throws javax.persistence.PersistenceException in case of JPA flushing errors
131 */
132 protected void flushIfNecessary(EntityManager em, boolean existingTransaction) throws PersistenceException {
133 if (isFlushEager()) {
134 logger.debug("Eagerly flushing JPA entity manager");
135 em.flush();
136 }
137 }
138
139 /**
140 * Convert the given runtime exception to an appropriate exception from the
141 * <code>org.springframework.dao</code> hierarchy if necessary, or
142 * return the exception itself if it is not persistence related
143 * <p>Default implementation delegates to the JpaDialect.
144 * May be overridden in subclasses.
145 * @param ex runtime exception that occured, which may or may not
146 * be JPA-related
147 * @return the corresponding DataAccessException instance if
148 * wrapping should occur, otherwise the raw exception
149 * @see org.springframework.dao.support.DataAccessUtils#translateIfNecessary
150 */
151 public RuntimeException translateIfNecessary(RuntimeException ex) {
152 return DataAccessUtils.translateIfNecessary(ex, getJpaDialect());
153 }
154
155 }