KickJava   Java API By Example, From Geeks To Geeks.

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


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.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.Map JavaDoc;
24
25 import javax.persistence.EntityManager;
26 import javax.persistence.EntityManagerFactory;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30
31 import org.springframework.util.CollectionUtils;
32
33 /**
34  * Factory for a shared JPA EntityManager for a given EntityManagerFactory.
35  *
36  * <p>The shared EntityManager will behave just like an EntityManager fetched
37  * from an application server's JNDI environment, as defined by the JPA
38  * specification. It will delegate all calls to the current transactional
39  * EntityManager, if any; else, it will fall back to a newly created
40  * EntityManager per operation.
41  *
42  * @author Juergen Hoeller
43  * @author Rod Johnson
44  * @since 2.0
45  * @see org.springframework.orm.jpa.LocalEntityManagerFactoryBean
46  * @see org.springframework.orm.jpa.JpaTransactionManager
47  */

48 public abstract class SharedEntityManagerCreator {
49
50     /**
51      * Create a shared transactional EntityManager proxy,
52      * given this EntityManagerFactory
53      * @param emf the EntityManagerFactory to delegate to.
54      * If this implements the EntityManagerFactoryInfo interface, appropriate handling
55      * of the native EntityManagerFactory and available EntityManagerPlusOperations
56      * will automatically apply.
57      * @return a shareable transaction EntityManager proxy
58      */

59     public static EntityManager createSharedEntityManager(EntityManagerFactory emf) {
60         return createSharedEntityManager(emf, null);
61     }
62
63     /**
64      * Create a shared transactional EntityManager proxy,
65      * given this EntityManagerFactory
66      * @param emf the EntityManagerFactory to delegate to.
67      * If this implements the EntityManagerFactoryInfo interface, appropriate handling
68      * of the native EntityManagerFactory and available EntityManagerPlusOperations
69      * will automatically apply.
70      * @param properties the properties to be passed into the <code>createEntityManager</code>
71      * call (may be <code>null</code>)
72      * @return a shareable transaction EntityManager proxy
73      */

74     public static EntityManager createSharedEntityManager(EntityManagerFactory emf, Map JavaDoc properties) {
75         Class JavaDoc[] entityManagerInterfaces = null;
76         if (emf instanceof EntityManagerFactoryInfo) {
77             EntityManagerFactoryInfo emfInfo = (EntityManagerFactoryInfo) emf;
78             Class JavaDoc entityManagerInterface = emfInfo.getEntityManagerInterface();
79             JpaDialect jpaDialect = emfInfo.getJpaDialect();
80             if (jpaDialect != null && jpaDialect.supportsEntityManagerPlusOperations()) {
81                 entityManagerInterfaces = new Class JavaDoc[] {entityManagerInterface, EntityManagerPlus.class};
82             }
83             else {
84                 entityManagerInterfaces = new Class JavaDoc[] {entityManagerInterface};
85             }
86         }
87         else {
88             entityManagerInterfaces = new Class JavaDoc[] {EntityManager.class};
89         }
90         return createSharedEntityManager(emf, properties, entityManagerInterfaces);
91     }
92
93     /**
94      * Create a shared transactional EntityManager proxy,
95      * given this EntityManagerFactory
96      * @param emf EntityManagerFactory to obtain EntityManagers from as needed
97      * @param properties the properties to be passed into the <code>createEntityManager</code>
98      * call (may be <code>null</code>)
99      * @param entityManagerInterfaces interfaces to be implemented by the
100      * EntityManager. Allows the addition or specification of proprietary interfaces.
101      * @return a shareable transaction EntityManager proxy
102      */

103     public static EntityManager createSharedEntityManager(
104             EntityManagerFactory emf, Map JavaDoc properties, Class JavaDoc... entityManagerInterfaces) {
105
106         return (EntityManager) Proxy.newProxyInstance(
107                 SharedEntityManagerCreator.class.getClassLoader(),
108                 entityManagerInterfaces,
109                 new SharedEntityManagerInvocationHandler(emf, properties));
110     }
111
112
113     /**
114      * Invocation handler that delegates all calls to the current
115      * transactional EntityManager, if any; else, it will fall back
116      * to a newly created EntityManager per operation.
117      */

118     private static class SharedEntityManagerInvocationHandler implements InvocationHandler JavaDoc {
119
120         private final Log logger = LogFactory.getLog(getClass());
121
122         private final EntityManagerFactory targetFactory;
123
124         private final Map JavaDoc properties;
125
126         public SharedEntityManagerInvocationHandler(EntityManagerFactory target, Map JavaDoc properties) {
127             this.targetFactory = target;
128             this.properties = properties;
129         }
130
131         public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args) throws Throwable JavaDoc {
132             // Invocation on EntityManager interface coming in...
133

134             if (method.getName().equals("equals")) {
135                 // Only consider equal when proxies are identical.
136
return (proxy == args[0]);
137             }
138             else if (method.getName().equals("hashCode")) {
139                 // Use hashCode of SessionFactory proxy.
140
return hashCode();
141             }
142             else if (method.getName().equals("isOpen")) {
143                 // Handle isOpen method: always return true.
144
return true;
145             }
146             else if (method.getName().equals("close")) {
147                 // Handle close method: suppress, not valid.
148
return null;
149             }
150             else if (method.getName().equals("getTransaction")) {
151                 throw new IllegalStateException JavaDoc(
152                         "Not allowed to create transaction on shared EntityManager - " +
153                         "use Spring transactions or EJB CMT instead");
154             }
155             else if (method.getName().equals("joinTransaction")) {
156                 throw new IllegalStateException JavaDoc(
157                         "Not allowed to join transaction on shared EntityManager - " +
158                         "use Spring transactions or EJB CMT instead");
159             }
160
161             // Determine current EntityManager: either the transactional one
162
// managed by the factory or a temporary one for the given invocation.
163
EntityManager target =
164                     EntityManagerFactoryUtils.doGetTransactionalEntityManager(this.targetFactory, this.properties);
165             boolean isNewEm = false;
166             if (target == null) {
167                 logger.debug("Creating new EntityManager for shared EntityManager invocation");
168                 target = (!CollectionUtils.isEmpty(this.properties) ?
169                         this.targetFactory.createEntityManager(this.properties) :
170                         this.targetFactory.createEntityManager());
171                 isNewEm = true;
172             }
173
174             // Invoke method on current EntityManager.
175
try {
176                 return method.invoke(target, args);
177             }
178             catch (InvocationTargetException JavaDoc ex) {
179                 throw ex.getTargetException();
180             }
181             finally {
182                 if (isNewEm) {
183                     target.close();
184                 }
185             }
186         }
187     }
188
189 }
190
Popular Tags