1 package org.wamblee.support.persistence;
3 import java.sql.SQLException;
5 import java.util.ServiceLoader;
6 import java.util.TreeMap;
7 import java.util.logging.Level;
8 import java.util.logging.Logger;
10 import javax.naming.InitialContext;
11 import javax.naming.NamingException;
12 import javax.persistence.EntityManager;
13 import javax.persistence.EntityManagerFactory;
14 import javax.persistence.EntityTransaction;
15 import javax.persistence.Persistence;
16 import javax.sql.DataSource;
18 import org.hibernate.ejb.HibernatePersistence;
19 import org.wamblee.support.jndi.StubInitialContextFactory;
20 import org.wamblee.support.persistence.toplink.JndiSessionCustomizer;
24 * Utility for building an appropriately configured EntityManagerFactory. The
25 * idea is that a persistence.xml is used unchanged from the production version.
26 * This utility will then add the additional properties required for execution
27 * in a standalone environment.
29 * The other purpose is to to shield dependencies of the test code on a
30 * particular JPA provider.
32 public class JpaBuilder {
34 private static final Logger LOGGER = Logger.getLogger(JpaBuilder.class
38 * Callback interface to execute some JPA code within a transaction with the
39 * entitymanager to use provided as input.
41 public static interface JpaUnitOfWork<T> {
43 * Executes the unit of work. A transaction has been started.
44 * @param em Entity manager.
45 * @return Result of the execute method. If you don't want to return anything use
46 * <code>Void</code> for the return type and return null from the implementation.
48 T execute(EntityManager em);
51 private PersistenceUnitDescription persistenceUnit;
52 private DataSource dataSource;
53 private EntityManagerFactory factory;
56 * Constructs the builder.
59 * Datasource of database.
60 * @param aPersistenceUnit
63 public JpaBuilder(DataSource aDataSource,
64 PersistenceUnitDescription aPersistenceUnit) {
65 persistenceUnit = aPersistenceUnit;
66 dataSource = aDataSource;
67 StubInitialContextFactory.register();
71 * Starts the builder, which in particular, mocks JNDI, binds the datasource
72 * the JNDI where the persistence unit expects it, creates the entity
73 * manager factory, and forces creation of the database schema.
75 public void start() throws Exception {
77 InitialContext ctx = new InitialContext();
78 ctx.bind(persistenceUnit.getJndiName(), dataSource);
79 } catch (NamingException e) {
80 throw new RuntimeException("JNDI problem", e);
82 factory = createFactory();
83 execute(new JpaUnitOfWork<Void>() {
84 public Void execute(EntityManager em) {
85 // Empty, just to trigger database schema creation.
92 * Stops the entity manager factory and disables JNDI mocking.
95 StubInitialContextFactory.unregister();
100 * Creates a new entity manager factory. Typically not used by test code.
101 * @return Entity manager factory.
103 public EntityManagerFactory createFactory() {
104 Map<String, String> jpaProps = new TreeMap<String, String>();
106 JpaCustomizerBuilder.getCustomizer().customize(persistenceUnit, jpaProps);
108 jpaProps.put("javax.persistence.provider", HibernatePersistence.class.getName() +"unknown");
109 EntityManagerFactory factory = Persistence.createEntityManagerFactory(persistenceUnit
110 .getUnitName(), jpaProps);
112 LOGGER.info("Using " + factory.getClass());
117 * Executes a unit of work. This creates an entitymanager and runs the
118 * {@link JpaUnitOfWork#execute(EntityManager)} within a transaction, passing
119 * it the entity manager. Use of this method saves a lot of typing for applications.
121 * @param aWork Work to execute.
122 * @return The return value of the execute method of the unit of work.
124 public <T> T execute(JpaUnitOfWork<T> aWork) throws Exception {
125 EntityManager em = factory.createEntityManager();
126 EntityTransaction transaction = em.getTransaction();
129 T value = aWork.execute(em);
130 transaction.commit();
132 } catch (Exception e) {
133 LOGGER.log(Level.WARNING, "Exception occured", e);
134 transaction.rollback();