KickJava   Java API By Example, From Geeks To Geeks.

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


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 java.lang.reflect.InvocationHandler JavaDoc;
20 import java.lang.reflect.InvocationTargetException JavaDoc;
21 import java.lang.reflect.Method JavaDoc;
22 import java.lang.reflect.Proxy JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.Map JavaDoc;
26 import java.util.Properties JavaDoc;
27
28 import javax.persistence.EntityManager;
29 import javax.persistence.EntityManagerFactory;
30 import javax.persistence.PersistenceException;
31 import javax.persistence.spi.PersistenceProvider;
32 import javax.persistence.spi.PersistenceUnitInfo;
33 import javax.sql.DataSource JavaDoc;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37
38 import org.springframework.beans.BeanUtils;
39 import org.springframework.beans.factory.DisposableBean;
40 import org.springframework.beans.factory.FactoryBean;
41 import org.springframework.beans.factory.InitializingBean;
42 import org.springframework.dao.DataAccessException;
43 import org.springframework.dao.support.PersistenceExceptionTranslator;
44 import org.springframework.util.Assert;
45 import org.springframework.util.ClassUtils;
46 import org.springframework.util.CollectionUtils;
47 import org.springframework.util.ObjectUtils;
48
49 /**
50  * Abstract {@link org.springframework.beans.factory.FactoryBean} that
51  * creates a local JPA {@link javax.persistence.EntityManagerFactory}
52  * instance within a Spring application context.
53  *
54  * <p>Encapsulates the common functionality between the different JPA
55  * bootstrap contracts (standalone as well as container).
56  *
57  * <p>Implements support for standard JPA configuration as well as
58  * Spring's {@link JpaVendorAdapter} abstraction, and controls the
59  * EntityManagerFactory's lifecycle.
60  *
61  * <p>This class also implements the
62  * {@link org.springframework.dao.support.PersistenceExceptionTranslator}
63  * interface, as autodetected by Spring's
64  * {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor},
65  * for AOP-based translation of native exceptions to Spring DataAccessExceptions.
66  * Hence, the presence of e.g. LocalEntityManagerFactoryBean automatically enables
67  * a PersistenceExceptionTranslationPostProcessor to translate JPA exceptions.
68  *
69  * @author Juergen Hoeller
70  * @author Rod Johnson
71  * @since 2.0
72  * @see LocalEntityManagerFactoryBean
73  * @see LocalContainerEntityManagerFactoryBean
74  */

75 public abstract class AbstractEntityManagerFactoryBean implements
76         FactoryBean, InitializingBean, DisposableBean, EntityManagerFactoryInfo, PersistenceExceptionTranslator {
77
78     /** Logger available to subclasses */
79     protected final Log logger = LogFactory.getLog(getClass());
80
81     private PersistenceProvider persistenceProvider;
82
83     private String JavaDoc persistenceUnitName;
84
85     private final Map JavaDoc jpaPropertyMap = new HashMap JavaDoc();
86
87     private Class JavaDoc<? extends EntityManager> entityManagerInterface;
88
89     private JpaDialect jpaDialect;
90
91     private JpaVendorAdapter jpaVendorAdapter;
92
93     /** Raw EntityManagerFactory as returned by the PersistenceProvider */
94     public EntityManagerFactory nativeEntityManagerFactory;
95
96     private EntityManagerFactory entityManagerFactory;
97
98
99     /**
100      * Set the PersistenceProvider implementation class to use for creating the
101      * EntityManagerFactory. If not specified, the persistence provider will be
102      * taken from the JpaVendorAdapter (if any) or retrieved through scanning
103      * (as far as possible).
104      * @see JpaVendorAdapter#getPersistenceProvider()
105      * @see javax.persistence.spi.PersistenceProvider
106      * @see javax.persistence.Persistence
107      */

108     public void setPersistenceProviderClass(Class JavaDoc<? extends PersistenceProvider> persistenceProviderClass) {
109         Assert.isAssignable(PersistenceProvider.class, persistenceProviderClass);
110         this.persistenceProvider = (PersistenceProvider) BeanUtils.instantiateClass(persistenceProviderClass);
111     }
112
113     /**
114      * Set the PersistenceProvider instance to use for creating the
115      * EntityManagerFactory. If not specified, the persistence provider
116      * will be taken from the JpaVendorAdapter (if any) or determined
117      * by the persistence unit deployment descriptor (as far as possible).
118      * @see JpaVendorAdapter#getPersistenceProvider()
119      * @see javax.persistence.spi.PersistenceProvider
120      * @see javax.persistence.Persistence
121      */

122     public void setPersistenceProvider(PersistenceProvider persistenceProvider) {
123         this.persistenceProvider = persistenceProvider;
124     }
125
126     public PersistenceProvider getPersistenceProvider() {
127         return this.persistenceProvider;
128     }
129
130     /**
131      * Specify the name of the EntityManagerFactory configuration.
132      * <p>Default is none, indicating the default EntityManagerFactory
133      * configuration. The persistence provider will throw an exception if
134      * ambiguous EntityManager configurations are found.
135      * @see javax.persistence.Persistence#createEntityManagerFactory(String)
136      */

137     public void setPersistenceUnitName(String JavaDoc persistenceUnitName) {
138         this.persistenceUnitName = persistenceUnitName;
139     }
140
141     public String JavaDoc getPersistenceUnitName() {
142         return this.persistenceUnitName;
143     }
144
145     /**
146      * Specify JPA properties, to be passed into
147      * <code>Persistence.createEntityManagerFactory</code> (if any).
148      * <p>Can be populated with a String "value" (parsed via PropertiesEditor) or a
149      * "props" element in XML bean definitions.
150      * @see javax.persistence.Persistence#createEntityManagerFactory(String, java.util.Map)
151      * @see javax.persistence.spi.PersistenceProvider#createContainerEntityManagerFactory(javax.persistence.spi.PersistenceUnitInfo, java.util.Map)
152      */

153     public void setJpaProperties(Properties JavaDoc jpaProperties) {
154         CollectionUtils.mergePropertiesIntoMap(jpaProperties, this.jpaPropertyMap);
155     }
156
157     /**
158      * Specify JPA properties as a Map, to be passed into
159      * <code>Persistence.createEntityManagerFactory</code> (if any).
160      * <p>Can be populated with a "map" or "props" element in XML bean definitions.
161      * @see javax.persistence.Persistence#createEntityManagerFactory(String, java.util.Map)
162      * @see javax.persistence.spi.PersistenceProvider#createContainerEntityManagerFactory(javax.persistence.spi.PersistenceUnitInfo, java.util.Map)
163      */

164     public void setJpaPropertyMap(Map JavaDoc jpaProperties) {
165         if (jpaProperties != null) {
166             this.jpaPropertyMap.putAll(jpaProperties);
167         }
168     }
169
170     /**
171      * Allow Map access to the JPA properties to be passed to the persistence
172      * provider, with the option to add or override specific entries.
173      * <p>Useful for specifying entries directly, for example via
174      * "jpaPropertyMap[myKey]".
175      */

176     public Map JavaDoc getJpaPropertyMap() {
177         return this.jpaPropertyMap;
178     }
179
180     /**
181      * Specify the (potentially vendor-specific) EntityManager interface that
182      * this factory's EntityManagers are supposed to implement.
183      * <p>The default will be taken from the specific JpaVendorAdapter, if any,
184      * or set to the standard <code>javax.persistence.EntityManager</code>
185      * interface else.
186      * @see JpaVendorAdapter#getEntityManagerInterface()
187      * @see EntityManagerFactoryInfo#getEntityManagerInterface()
188      */

189     public void setEntityManagerInterface(Class JavaDoc<? extends EntityManager> entityManagerInterface) {
190         Assert.isAssignable(EntityManager.class, entityManagerInterface);
191         this.entityManagerInterface = entityManagerInterface;
192     }
193
194     public Class JavaDoc<? extends EntityManager> getEntityManagerInterface() {
195         return this.entityManagerInterface;
196     }
197
198     /**
199      * Specify the vendor-specific JpaDialect implementation to associate with
200      * this EntityManagerFactory. This will be exposed through the
201      * EntityManagerFactoryInfo interface, to be picked up as default dialect by
202      * accessors that intend to use JpaDialect functionality.
203      * @see EntityManagerFactoryInfo#getJpaDialect()
204      */

205     public void setJpaDialect(JpaDialect jpaDialect) {
206         this.jpaDialect = jpaDialect;
207     }
208
209     public JpaDialect getJpaDialect() {
210         return this.jpaDialect;
211     }
212
213     /**
214      * Specify the JpaVendorAdapter implementation for the desired JPA provider,
215      * if any. This will initialize appropriate defaults for the given provider,
216      * such as persistence provider class and JpaDialect, unless locally
217      * overridden in this FactoryBean.
218      */

219     public void setJpaVendorAdapter(JpaVendorAdapter jpaVendorAdapter) {
220         this.jpaVendorAdapter = jpaVendorAdapter;
221     }
222
223
224     public final void afterPropertiesSet() throws PersistenceException {
225         if (this.jpaVendorAdapter != null) {
226             if (this.persistenceProvider == null) {
227                 this.persistenceProvider = this.jpaVendorAdapter.getPersistenceProvider();
228             }
229             Map JavaDoc vendorPropertyMap = this.jpaVendorAdapter.getJpaPropertyMap();
230             if (vendorPropertyMap != null) {
231                 for (Iterator JavaDoc it = vendorPropertyMap.entrySet().iterator(); it.hasNext();) {
232                     Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
233                     if (!this.jpaPropertyMap.containsKey(entry.getKey())) {
234                         this.jpaPropertyMap.put(entry.getKey(), entry.getValue());
235                     }
236                 }
237             }
238             if (this.entityManagerInterface == null) {
239                 this.entityManagerInterface = this.jpaVendorAdapter.getEntityManagerInterface();
240             }
241             if (this.jpaDialect == null) {
242                 this.jpaDialect = this.jpaVendorAdapter.getJpaDialect();
243             }
244         }
245         else {
246             if (this.entityManagerInterface == null) {
247                 this.entityManagerInterface = EntityManager.class;
248             }
249         }
250
251         this.nativeEntityManagerFactory = createNativeEntityManagerFactory();
252         if (this.jpaVendorAdapter != null) {
253             this.jpaVendorAdapter.postProcessEntityManagerFactory(this.nativeEntityManagerFactory);
254         }
255
256         // Wrap the EntityManagerFactory in a factory implementing all its interfaces.
257
// This allows interception of createEntityManager methods to return an
258
// application-managed EntityManager proxy that automatically joins
259
// existing transactions.
260
this.entityManagerFactory = createEntityManagerFactoryProxy(this.nativeEntityManagerFactory);
261     }
262
263     /**
264      * Create a proxy of the given EntityManagerFactory. We do this to be able
265      * to return transaction-aware proxies for application-managed
266      * EntityManagers, and to introduce the NamedEntityManagerFactory interface
267      * @param emf EntityManagerFactory as returned by the persistence provider
268      * @return proxy entity manager
269      */

270     protected EntityManagerFactory createEntityManagerFactoryProxy(EntityManagerFactory emf) {
271         // Automatically implement all interfaces implemented by the EntityManagerFactory.
272
Class JavaDoc[] ifcs = ClassUtils.getAllInterfaces(emf);
273         ifcs = (Class JavaDoc[]) ObjectUtils.addObjectToArray(ifcs, EntityManagerFactoryInfo.class);
274         EntityManagerFactoryPlusOperations plusOperations = null;
275         if (getJpaDialect() != null && getJpaDialect().supportsEntityManagerFactoryPlusOperations()) {
276             plusOperations = getJpaDialect().getEntityManagerFactoryPlusOperations(emf);
277             ifcs = (Class JavaDoc[]) ObjectUtils.addObjectToArray(ifcs, EntityManagerFactoryPlusOperations.class);
278         }
279         return (EntityManagerFactory) Proxy.newProxyInstance(getClass().getClassLoader(), ifcs,
280                 new ManagedEntityManagerFactoryInvocationHandler(emf, this, plusOperations));
281     }
282
283     /**
284      * Subclasses must implement this method to create the EntityManagerFactory
285      * that will be returned by the getObject() method
286      * @return EntityManagerFactory instance returned by this FactoryBean
287      * @throws PersistenceException if the EntityManager cannot be created
288      */

289     protected abstract EntityManagerFactory createNativeEntityManagerFactory() throws PersistenceException;
290
291
292     /**
293      * Implementation of the PersistenceExceptionTranslator interface, as
294      * autodetected by Spring's PersistenceExceptionTranslationPostProcessor.
295      * <p>Uses the dialect's conversion if possible; otherwise falls back to
296      * standard JPA exception conversion.
297      * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
298      * @see JpaDialect#translateExceptionIfPossible
299      * @see EntityManagerFactoryUtils#convertJpaAccessExceptionIfPossible
300      */

301     public DataAccessException translateExceptionIfPossible(RuntimeException JavaDoc ex) {
302         return (this.jpaDialect != null ? this.jpaDialect.translateExceptionIfPossible(ex) :
303                 EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(ex));
304     }
305
306     public EntityManagerFactory getNativeEntityManagerFactory() {
307         return this.nativeEntityManagerFactory;
308     }
309
310     public PersistenceUnitInfo getPersistenceUnitInfo() {
311         return null;
312     }
313
314     public DataSource JavaDoc getDataSource() {
315         return null;
316     }
317
318
319     /**
320      * Return the singleton EntityManagerFactory.
321      */

322     public EntityManagerFactory getObject() {
323         return this.entityManagerFactory;
324     }
325
326     public Class JavaDoc getObjectType() {
327         return (this.entityManagerFactory != null ? this.entityManagerFactory.getClass() : EntityManagerFactory.class);
328     }
329
330     public boolean isSingleton() {
331         return true;
332     }
333
334
335     /**
336      * Close the EntityManagerFactory on bean factory shutdown.
337      */

338     public void destroy() {
339         logger.info("Closing JPA EntityManagerFactory for <" + persistenceUnitName + ">");
340         this.entityManagerFactory.close();
341     }
342
343
344     /**
345      * Dynamic proxy invocation handler proxying an EntityManagerFactory to
346      * return a proxy EntityManager if necessary from createEntityManager()
347      * methods.
348      */

349     private static class ManagedEntityManagerFactoryInvocationHandler implements InvocationHandler JavaDoc {
350
351         private final EntityManagerFactory targetEntityManagerFactory;
352
353         private final EntityManagerFactoryInfo entityManagerFactoryInfo;
354
355         private final EntityManagerFactoryPlusOperations entityManagerFactoryPlusOperations;
356
357         private final JpaDialect jpaDialect;
358
359         public ManagedEntityManagerFactoryInvocationHandler(EntityManagerFactory targetEmf,
360                 EntityManagerFactoryInfo emfInfo, EntityManagerFactoryPlusOperations entityManagerFactoryPlusOperations) {
361
362             this.targetEntityManagerFactory = targetEmf;
363             this.entityManagerFactoryInfo = emfInfo;
364             this.entityManagerFactoryPlusOperations = entityManagerFactoryPlusOperations;
365             this.jpaDialect = emfInfo.getJpaDialect();
366         }
367
368         public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args) throws Throwable JavaDoc {
369             try {
370                 if (method.getDeclaringClass().isAssignableFrom(EntityManagerFactoryInfo.class)) {
371                     return method.invoke(this.entityManagerFactoryInfo, args);
372                 }
373                 if (method.getDeclaringClass().equals(EntityManagerFactoryPlusOperations.class)) {
374                     return method.invoke(this.entityManagerFactoryPlusOperations, args);
375                 }
376                 Object JavaDoc retVal = method.invoke(this.targetEntityManagerFactory, args);
377                 if (retVal instanceof EntityManager) {
378                     EntityManager rawEntityManager = (EntityManager) retVal;
379                     EntityManagerPlusOperations plusOperations = null;
380                     if (this.jpaDialect != null && this.jpaDialect.supportsEntityManagerPlusOperations()) {
381                         plusOperations = this.jpaDialect.getEntityManagerPlusOperations(rawEntityManager);
382                     }
383                     retVal = ExtendedEntityManagerCreator.createApplicationManagedEntityManager(
384                             rawEntityManager, plusOperations, this.jpaDialect);
385                 }
386                 return retVal;
387             }
388             catch (InvocationTargetException JavaDoc ex) {
389                 throw ex.getTargetException();
390             }
391         }
392     }
393
394 }
395
Popular Tags