KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > orm > jpa > EntityManagerFactoryUtils


1 /*
2  * Copyright 2002-2006 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 java.util.Map JavaDoc;
20
21 import javax.persistence.EntityExistsException;
22 import javax.persistence.EntityManager;
23 import javax.persistence.EntityManagerFactory;
24 import javax.persistence.EntityNotFoundException;
25 import javax.persistence.NoResultException;
26 import javax.persistence.NonUniqueResultException;
27 import javax.persistence.OptimisticLockException;
28 import javax.persistence.PersistenceException;
29 import javax.persistence.TransactionRequiredException;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33
34 import org.springframework.dao.DataAccessException;
35 import org.springframework.dao.DataAccessResourceFailureException;
36 import org.springframework.dao.DataIntegrityViolationException;
37 import org.springframework.dao.EmptyResultDataAccessException;
38 import org.springframework.dao.IncorrectResultSizeDataAccessException;
39 import org.springframework.dao.InvalidDataAccessApiUsageException;
40 import org.springframework.jdbc.datasource.DataSourceUtils;
41 import org.springframework.transaction.support.TransactionSynchronizationAdapter;
42 import org.springframework.transaction.support.TransactionSynchronizationManager;
43 import org.springframework.util.Assert;
44 import org.springframework.util.CollectionUtils;
45
46 /**
47  * Helper class featuring methods for JPA EntityManager handling,
48  * allowing for reuse of EntityManager instances within transactions.
49  * Also provides support for exception translation.
50  *
51  * <p>Mainly intended for internal use within the framework.
52  *
53  * @author Juergen Hoeller
54  * @since 2.0
55  */

56 public abstract class EntityManagerFactoryUtils {
57
58     /**
59      * Order value for TransactionSynchronization objects that clean up JPA
60      * EntityManagers. Return DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100
61      * to execute EntityManager cleanup before JDBC Connection cleanup, if any.
62      * @see org.springframework.jdbc.datasource.DataSourceUtils#CONNECTION_SYNCHRONIZATION_ORDER
63      */

64     public static final int ENTITY_MANAGER_SYNCHRONIZATION_ORDER =
65             DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100;
66
67     private static final Log logger = LogFactory.getLog(EntityManagerFactoryUtils.class);
68
69
70     /**
71      * Obtain a JPA EntityManager from the given factory. Is aware of a
72      * corresponding EntityManager bound to the current thread,
73      * for example when using JpaTransactionManager.
74      * <p>Note: Will return <code>null</code> if no thread-bound EntityManager found!
75      * @param emf EntityManagerFactory to create the EntityManager with
76      * @return the EntityManager, or <code>null</code> if none found
77      * @throws DataAccessResourceFailureException if the EntityManager couldn't be obtained
78      * @see JpaTransactionManager
79      */

80     public static EntityManager getTransactionalEntityManager(EntityManagerFactory emf)
81             throws DataAccessResourceFailureException {
82
83         return getTransactionalEntityManager(emf, null);
84     }
85
86     /**
87      * Obtain a JPA EntityManager from the given factory. Is aware of a
88      * corresponding EntityManager bound to the current thread,
89      * for example when using JpaTransactionManager.
90      * <p>Note: Will return <code>null</code> if no thread-bound EntityManager found!
91      * @param emf EntityManagerFactory to create the EntityManager with
92      * @param properties the properties to be passed into the <code>createEntityManager</code>
93      * call (may be <code>null</code>)
94      * @return the EntityManager, or <code>null</code> if none found
95      * @throws DataAccessResourceFailureException if the EntityManager couldn't be obtained
96      * @see JpaTransactionManager
97      */

98     public static EntityManager getTransactionalEntityManager(EntityManagerFactory emf, Map JavaDoc properties)
99             throws DataAccessResourceFailureException {
100         try {
101             return doGetTransactionalEntityManager(emf, properties);
102         }
103         catch (PersistenceException ex) {
104             throw new DataAccessResourceFailureException("Could not obtain JPA EntityManager", ex);
105         }
106     }
107
108     /**
109      * Obtain a JPA EntityManager from the given factory. Is aware of a
110      * corresponding EntityManager bound to the current thread,
111      * for example when using JpaTransactionManager.
112      * <p>Same as <code>getEntityManager</code>, but throwing the original PersistenceException.
113      * @param emf EntityManagerFactory to create the EntityManager with
114      * @param properties the properties to be passed into the <code>createEntityManager</code>
115      * call (may be <code>null</code>)
116      * @return the EntityManager, or <code>null</code> if none found
117      * @throws javax.persistence.PersistenceException if the EntityManager couldn't be created
118      * @see #getTransactionalEntityManager(javax.persistence.EntityManagerFactory)
119      * @see JpaTransactionManager
120      */

121     public static EntityManager doGetTransactionalEntityManager(
122             EntityManagerFactory emf, Map JavaDoc properties) throws PersistenceException {
123
124         Assert.notNull(emf, "No EntityManagerFactory specified");
125
126         EntityManagerHolder emHolder =
127                 (EntityManagerHolder) TransactionSynchronizationManager.getResource(emf);
128         if (emHolder != null) {
129             if (!emHolder.isSynchronizedWithTransaction() &&
130                     TransactionSynchronizationManager.isSynchronizationActive()) {
131                 // Try to explicitly synchronize the EntityManager itself
132
// with an ongoing JTA transaction, if any.
133
try {
134                     emHolder.getEntityManager().joinTransaction();
135                 }
136                 catch (TransactionRequiredException ex) {
137                     logger.debug("Could not join JTA transaction because none was active", ex);
138                 }
139                 emHolder.setSynchronizedWithTransaction(true);
140                 TransactionSynchronizationManager.registerSynchronization(
141                         new EntityManagerSynchronization(emHolder, emf, false));
142             }
143             return emHolder.getEntityManager();
144         }
145
146         if (!TransactionSynchronizationManager.isSynchronizationActive()) {
147             // Indicate that we can't obtain a transactional EntityManager.
148
return null;
149         }
150
151         // Create a new EntityManager for use within the current transaction.
152
logger.debug("Opening JPA EntityManager");
153         EntityManager em =
154                 (!CollectionUtils.isEmpty(properties) ? emf.createEntityManager(properties) : emf.createEntityManager());
155
156         if (TransactionSynchronizationManager.isSynchronizationActive()) {
157             logger.debug("Registering transaction synchronization for JPA EntityManager");
158             // Use same EntityManager for further JPA actions within the transaction.
159
// Thread object will get removed by synchronization at transaction completion.
160
emHolder = new EntityManagerHolder(em);
161             emHolder.setSynchronizedWithTransaction(true);
162             TransactionSynchronizationManager.registerSynchronization(
163                     new EntityManagerSynchronization(emHolder, emf, true));
164             TransactionSynchronizationManager.bindResource(emf, emHolder);
165         }
166
167         return em;
168     }
169
170     /**
171      * Convert the given runtime exception to an appropriate exception from the
172      * <code>org.springframework.dao</code> hierarchy.
173      * Return null if no translation is appropriate: any other exception may
174      * have resulted from user code, and should not be translated.
175      * <p>The most important cases like object not found or optimistic locking
176      * failure are covered here. For more fine-granular conversion, JpaAccessor and
177      * JpaTransactionManager support sophisticated translation of exceptions via a
178      * JpaDialect.
179      * @param ex runtime exception that occured
180      * @return the corresponding DataAccessException instance,
181      * or <code>null</code> if the exception should not be translated
182      */

183     public static DataAccessException convertJpaAccessExceptionIfPossible(RuntimeException JavaDoc ex) {
184         // Following the JPA specification, a persistence provider can also
185
// throw these two exceptions, besides PersistenceException.
186
if (ex instanceof IllegalStateException JavaDoc) {
187             return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
188         }
189         if (ex instanceof IllegalArgumentException JavaDoc) {
190             return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
191         }
192
193         // Check for well-known PersistenceException subclasses.
194
if (ex instanceof EntityNotFoundException) {
195             return new JpaObjectRetrievalFailureException((EntityNotFoundException) ex);
196         }
197         if (ex instanceof NoResultException) {
198             return new EmptyResultDataAccessException(ex.getMessage(), 1);
199         }
200         if (ex instanceof NonUniqueResultException) {
201             return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1);
202         }
203         if (ex instanceof OptimisticLockException) {
204             return new JpaOptimisticLockingFailureException((OptimisticLockException) ex);
205         }
206         if (ex instanceof EntityExistsException) {
207             return new DataIntegrityViolationException(ex.getMessage(), ex);
208         }
209         if (ex instanceof TransactionRequiredException) {
210             return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
211         }
212
213         // If we have another kind of PersistenceException, throw it.
214
if (ex instanceof PersistenceException) {
215             return new JpaSystemException((PersistenceException) ex);
216         }
217         
218         // If we get here, we have an exception that resulted from user code,
219
// rather than the persistence provider, so we return null to indicate
220
// that translation should not occur.
221
return null;
222     }
223
224
225     /**
226      * Callback for resource cleanup at the end of a non-JPA transaction
227      * (e.g. when participating in a JtaTransactionManager transaction).
228      * @see org.springframework.transaction.jta.JtaTransactionManager
229      */

230     private static class EntityManagerSynchronization extends TransactionSynchronizationAdapter {
231
232         private final EntityManagerHolder entityManagerHolder;
233
234         private final EntityManagerFactory entityManagerFactory;
235
236         private final boolean newEntityManager;
237
238         private boolean holderActive = true;
239
240         public EntityManagerSynchronization(
241                 EntityManagerHolder emHolder, EntityManagerFactory emf, boolean newEntityManager) {
242             this.entityManagerHolder = emHolder;
243             this.entityManagerFactory = emf;
244             this.newEntityManager = newEntityManager;
245         }
246
247         public int getOrder() {
248             return ENTITY_MANAGER_SYNCHRONIZATION_ORDER;
249         }
250
251         public void suspend() {
252             if (this.holderActive) {
253                 TransactionSynchronizationManager.unbindResource(this.entityManagerFactory);
254             }
255         }
256
257         public void resume() {
258             if (this.holderActive) {
259                 TransactionSynchronizationManager.bindResource(this.entityManagerFactory, this.entityManagerHolder);
260             }
261         }
262
263         public void beforeCompletion() {
264             if (this.newEntityManager) {
265                 TransactionSynchronizationManager.unbindResource(this.entityManagerFactory);
266                 this.holderActive = false;
267                 this.entityManagerHolder.getEntityManager().close();
268             }
269         }
270
271         public void afterCompletion(int status) {
272             if (!this.newEntityManager && status != STATUS_COMMITTED) {
273                 // Clear all pending inserts/updates/deletes in the EntityManager.
274
// Necessary for pre-bound EntityManagers, to avoid inconsistent state.
275
this.entityManagerHolder.getEntityManager().clear();
276             }
277             this.entityManagerHolder.setSynchronizedWithTransaction(false);
278         }
279     }
280
281 }
282
Popular Tags