2 * Copyright 2005-2010 the original author or authors.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org.wamblee.test.persistence;
19 import java.util.TreeMap;
20 import java.util.logging.Level;
21 import java.util.logging.Logger;
23 import javax.persistence.EntityManager;
24 import javax.persistence.EntityManagerFactory;
25 import javax.persistence.EntityTransaction;
26 import javax.persistence.Persistence;
27 import javax.persistence.PersistenceException;
29 import org.wamblee.general.ThreadSpecificProxyFactory;
30 import org.wamblee.test.jndi.StubInitialContextFactory;
31 import org.wamblee.test.transactions.TransactionResource;
34 * Utility for building an appropriately configured EntityManagerFactory. The
35 * idea is that a persistence.xml is used unchanged from the production version.
36 * This utility will then add the additional properties required for execution
37 * in a standalone environment.
39 * The other purpose is to to shield dependencies of the test code on a
40 * particular JPA provider.
42 public class JpaBuilder implements TransactionResource<EntityManager> {
44 private static final Logger LOGGER = Logger.getLogger(JpaBuilder.class
48 * Callback interface to execute some JPA code within a transaction with the
49 * entitymanager to use provided as input.
51 public static interface JpaUnitOfWork<T> {
53 * Executes the unit of work. A transaction has been started.
57 * @return Result of the execute method. If you don't want to return
58 * anything use <code>Void</code> for the return type and return
59 * null from the implementation.
61 T execute(EntityManager aEm) throws Exception;
64 private PersistenceUnitDescription persistenceUnit;
67 private String password;
68 private EntityManagerFactory factory;
69 private ThreadSpecificProxyFactory<EntityManager> entityManager;
72 * Constructs the builder.
80 * @param aPersistenceUnit
83 public JpaBuilder(String aUrl, String aUser, String aPassword,
84 PersistenceUnitDescription aPersistenceUnit) {
85 persistenceUnit = aPersistenceUnit;
89 entityManager = new ThreadSpecificProxyFactory<EntityManager>(EntityManager.class);
93 * Starts the builder, which in particular, mocks JNDI, binds the datasource
94 * the JNDI where the persistence unit expects it, creates the entity
95 * manager factory, and forces creation of the database schema.
97 public void start() throws Exception {
98 factory = createFactory();
100 execute(new JpaUnitOfWork<Void>() {
101 public Void execute(EntityManager aEm) {
102 // Empty, just to trigger database schema creation.
106 } catch (PersistenceException e) {
113 * Stops the entity manager factory and disables JNDI mocking.
116 StubInitialContextFactory.unregister();
121 * Creates a new entity manager factory. Typically not used by test code.
123 * @return Entity manager factory.
125 public EntityManagerFactory createFactory() {
126 Map<String, String> jpaProps = new TreeMap<String, String>();
128 jpaProps.put("javax.persistence.jtaDataSource", null);
129 jpaProps.put("javax.persistence.transactionType", "RESOURCE_LOCAL");
130 jpaProps.put("javax.persistence.jdbc.url", url);
131 jpaProps.put("javax.persistence.jdbc.user", user);
132 jpaProps.put("javax.persistence.jdbc.password", password);
134 JpaCustomizerBuilder.getCustomizer().customize(persistenceUnit,
137 // jpaProps.put("javax.persistence.provider",
138 // HibernatePersistence.class.getName());
139 EntityManagerFactory emf = Persistence.createEntityManagerFactory(
140 persistenceUnit.getUnitName(), jpaProps);
142 LOGGER.info("Using " + emf.getClass());
147 * Executes a unit of work. This creates an entitymanager and runs the
148 * {@link JpaUnitOfWork#execute(EntityManager)} within a transaction,
149 * passing it the entity manager. Use of this method saves a lot of typing
154 * @return The return value of the execute method of the unit of work.
156 public <T> T execute(JpaUnitOfWork<T> aWork) throws Exception {
157 EntityManager em = begin();
159 T value = aWork.execute(em);
162 } catch (Exception e) {
163 LOGGER.log(Level.WARNING, "Exception occured", e);
170 public EntityManager begin() {
171 EntityManager em = factory.createEntityManager();
172 EntityTransaction transaction = em.getTransaction();
174 entityManager.set(em);
179 public void commit(EntityManager aEntityManager) {
181 aEntityManager.getTransaction().commit();
183 aEntityManager.close();
184 entityManager.set(null);
189 public void rollback(EntityManager aEntityManager) {
191 aEntityManager.getTransaction().rollback();
193 aEntityManager.close();
194 entityManager.set(null);
199 * Gets a contextual reference to an entity manager that delegates to the
200 * appropriate (current) one which is active for the current transaction.
201 * @return EntityManager.
203 public EntityManager getContextualEntityManager() {
204 return entityManager.getProxy();