1 /**
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one or more
4 * contributor license agreements. See the NOTICE file distributed with
5 * this work for additional information regarding copyright ownership.
6 * The ASF licenses this file to You under the Apache License, Version 2.0
7 * (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 package org.apache.openejb.persistence;
19
20 import java.util.Map;
21 import javax.persistence.FlushModeType;
22 import javax.persistence.LockModeType;
23 import javax.persistence.Query;
24 import javax.persistence.EntityTransaction;
25 import javax.persistence.EntityManager;
26 import javax.persistence.EntityManagerFactory;
27 import javax.persistence.TransactionRequiredException;
28
29 /**
30 * The JtaEntityManager is a wrapper around an entity manager that automatically creates and closes entity managers
31 * for each transaction in which it is accessed. This implementation supports both transaction and extended scoped
32 * JTA entity managers.
33 * </p>
34 * It is important that extended scoped entity managers add entity managers to the JtaEntityManagerRegistry when the
35 * component is entered and remove them when exited. If this registration is not preformed, an IllegalStateException
36 * will be thrown when entity manger is used.
37 * It is important that a component adds extended scoped entity managers to the JtaEntityManagerRegistry when the
38 * component is entered and removes them when exited. If this registration is not preformed, an IllegalStateException will
39 * be thrown when entity manger is accessed.
40 */
41 public class JtaEntityManager implements EntityManager {
42 private final JtaEntityManagerRegistry registry;
43 private final EntityManagerFactory entityManagerFactory;
44 private final Map properties;
45 private final boolean extended;
46
47 public JtaEntityManager(JtaEntityManagerRegistry registry, EntityManagerFactory entityManagerFactory, Map properties) {
48 this(registry, entityManagerFactory, properties, false);
49
50 }
51 public JtaEntityManager(JtaEntityManagerRegistry registry, EntityManagerFactory entityManagerFactory, Map properties, boolean extended) {
52 if (registry == null) throw new NullPointerException("registry is null");
53 if (entityManagerFactory == null) throw new NullPointerException("entityManagerFactory is null");
54 this.registry = registry;
55 this.entityManagerFactory = entityManagerFactory;
56 this.properties = properties;
57 this.extended = extended;
58 }
59
60 private EntityManager getEntityManager() {
61 return registry.getEntityManager(entityManagerFactory, properties, extended);
62 }
63
64 private boolean isTransactionActive() {
65 return registry.isTransactionActive();
66 }
67
68 /**
69 * This method assures that a non-extended entity managers has an acive transaction. This is
70 * required for some operations on the entity manager.
71 * @throws TransactionRequiredException if non-extended and a transaction is not active
72 */
73 private void assertTransactionActive() throws TransactionRequiredException {
74 if (!extended && !isTransactionActive()) {
75 throw new TransactionRequiredException();
76 }
77 }
78
79 /**
80 * Closes a non-extended entity manager if no transaction is active. For methods on an
81 * entity manager that do not require an active transaction, a temp entity manager is created
82 * for the operation and then closed.
83 * @param entityManager the entity manager to close if non-extended and a transaction is not active
84 */
85 private void closeIfNoTx(EntityManager entityManager) {
86 if (!extended && !isTransactionActive()) {
87 entityManager.close();
88 }
89 }
90
91 public EntityManager getDelegate() {
92 return getEntityManager();
93 }
94
95 public void persist(Object entity) {
96 assertTransactionActive();
97 getEntityManager().persist(entity);
98 }
99
100 public <T>T merge(T entity) {
101 assertTransactionActive();
102 return getEntityManager().merge(entity);
103 }
104
105 public void remove(Object entity) {
106 assertTransactionActive();
107 getEntityManager().remove(entity);
108 }
109
110 public <T>T find(Class<T> entityClass, Object primaryKey) {
111 EntityManager entityManager = getEntityManager();
112 try {
113 return entityManager.find(entityClass, primaryKey);
114 } finally {
115 closeIfNoTx(entityManager);
116 }
117 }
118
119 public <T>T getReference(Class<T> entityClass, Object primaryKey) {
120 EntityManager entityManager = getEntityManager();
121 try {
122 return entityManager.getReference(entityClass, primaryKey);
123 } finally {
124 closeIfNoTx(entityManager);
125 }
126 }
127
128 public void flush() {
129 assertTransactionActive();
130 getEntityManager().flush();
131 }
132
133 public void setFlushMode(FlushModeType flushMode) {
134 EntityManager entityManager = getEntityManager();
135 try {
136 entityManager.setFlushMode(flushMode);
137 } finally {
138 closeIfNoTx(entityManager);
139 }
140 }
141
142 public FlushModeType getFlushMode() {
143 EntityManager entityManager = getEntityManager();
144 try {
145 return entityManager.getFlushMode();
146 } finally {
147 closeIfNoTx(entityManager);
148 }
149 }
150
151 public void lock(Object entity, LockModeType lockMode) {
152 assertTransactionActive();
153 getEntityManager().lock(entity, lockMode);
154 }
155
156 public void refresh(Object entity) {
157 assertTransactionActive();
158 getEntityManager().refresh(entity);
159 }
160
161 public void clear() {
162 if (!isTransactionActive()) {
163 return;
164 }
165 getEntityManager().clear();
166 }
167
168 public boolean contains(Object entity) {
169 return isTransactionActive() && getEntityManager().contains(entity);
170 }
171
172 public Query createQuery(String qlString) {
173 EntityManager entityManager = getEntityManager();
174 Query query = entityManager.createQuery(qlString);
175 return proxyIfNoTx(entityManager, query);
176 }
177
178 public Query createNamedQuery(String name) {
179 EntityManager entityManager = getEntityManager();
180 Query query = entityManager.createNamedQuery(name);
181 return proxyIfNoTx(entityManager, query);
182 }
183
184 public Query createNativeQuery(String sqlString) {
185 EntityManager entityManager = getEntityManager();
186 Query query = entityManager.createNativeQuery(sqlString);
187 return proxyIfNoTx(entityManager, query);
188 }
189
190 public Query createNativeQuery(String sqlString, Class resultClass) {
191 EntityManager entityManager = getEntityManager();
192 Query query = entityManager.createNativeQuery(sqlString, resultClass);
193 return proxyIfNoTx(entityManager, query);
194 }
195
196 public Query createNativeQuery(String sqlString, String resultSetMapping) {
197 EntityManager entityManager = getEntityManager();
198 Query query = entityManager.createNativeQuery(sqlString, resultSetMapping);
199 return proxyIfNoTx(entityManager, query);
200 }
201
202 private Query proxyIfNoTx(EntityManager entityManager, Query query) {
203 if (!extended && !isTransactionActive()) {
204 return new JtaQuery(entityManager, query);
205 }
206 return query;
207 }
208
209 public void joinTransaction() {
210 }
211
212 public void close() {
213 }
214
215 public boolean isOpen() {
216 return true;
217 }
218
219 public EntityTransaction getTransaction() {
220 throw new IllegalStateException("A JTA Entity Manager can not use an entity transaction");
221 }
222 }