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 (!extended && !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 EntityManager can not use the EntityTransaction API. See JPA 1.0 section 5.5"); 221 } 222 }