1 package org.wamblee.support.persistence;
4 import java.util.TreeMap;
5 import java.util.logging.Level;
6 import java.util.logging.Logger;
8 import javax.naming.InitialContext;
9 import javax.naming.NamingException;
10 import javax.persistence.EntityManager;
11 import javax.persistence.EntityManagerFactory;
12 import javax.persistence.EntityTransaction;
13 import javax.persistence.Persistence;
14 import javax.sql.DataSource;
16 import org.wamblee.support.jndi.StubInitialContextFactory;
20 * Utility for building an appropriately configured EntityManagerFactory. The
21 * idea is that a persistence.xml is used unchanged from the production version.
22 * This utility will then add the additional properties required for execution
23 * in a standalone environment.
25 * The other purpose is to to shield dependencies of the test code on a
26 * particular JPA provider.
28 public class JpaBuilder {
30 private static final Logger LOGGER = Logger.getLogger(JpaBuilder.class
34 * Callback interface to execute some JPA code within a transaction with the
35 * entitymanager to use provided as input.
37 public static interface JpaUnitOfWork<T> {
39 * Executes the unit of work. A transaction has been started.
40 * @param em Entity manager.
41 * @return Result of the execute method. If you don't want to return anything use
42 * <code>Void</code> for the return type and return null from the implementation.
44 T execute(EntityManager em);
47 private PersistenceUnitDescription persistenceUnit;
48 private DataSource dataSource;
49 private EntityManagerFactory factory;
52 * Constructs the builder.
55 * Datasource of database.
56 * @param aPersistenceUnit
59 public JpaBuilder(DataSource aDataSource,
60 PersistenceUnitDescription aPersistenceUnit) {
61 persistenceUnit = aPersistenceUnit;
62 dataSource = aDataSource;
63 StubInitialContextFactory.register();
67 * Starts the builder, which in particular, mocks JNDI, binds the datasource
68 * the JNDI where the persistence unit expects it, creates the entity
69 * manager factory, and forces creation of the database schema.
71 public void start() throws Exception {
73 InitialContext ctx = new InitialContext();
74 ctx.bind(persistenceUnit.getJndiName(), dataSource);
75 } catch (NamingException e) {
76 throw new RuntimeException("JNDI problem", e);
78 factory = createFactory();
79 execute(new JpaUnitOfWork<Void>() {
80 public Void execute(EntityManager em) {
81 // Empty, just to trigger database schema creation.
88 * Stops the entity manager factory and disables JNDI mocking.
91 StubInitialContextFactory.unregister();
96 * Creates a new entity manager factory. Typically not used by test code.
97 * @return Entity manager factory.
99 public EntityManagerFactory createFactory() {
100 Map<String, String> jpaProps = new TreeMap<String, String>();
102 JpaCustomizerBuilder.getCustomizer().customize(persistenceUnit, jpaProps);
104 //jpaProps.put("javax.persistence.provider", HibernatePersistence.class.getName());
105 EntityManagerFactory factory = Persistence.createEntityManagerFactory(persistenceUnit
106 .getUnitName(), jpaProps);
108 LOGGER.info("Using " + factory.getClass());
113 * Executes a unit of work. This creates an entitymanager and runs the
114 * {@link JpaUnitOfWork#execute(EntityManager)} within a transaction, passing
115 * it the entity manager. Use of this method saves a lot of typing for applications.
117 * @param aWork Work to execute.
118 * @return The return value of the execute method of the unit of work.
120 public <T> T execute(JpaUnitOfWork<T> aWork) throws Exception {
121 EntityManager em = factory.createEntityManager();
122 EntityTransaction transaction = em.getTransaction();
125 T value = aWork.execute(em);
126 transaction.commit();
128 } catch (Exception e) {
129 LOGGER.log(Level.WARNING, "Exception occured", e);
130 transaction.rollback();