1 package org.wamblee.support.persistence;
3 import java.sql.SQLException;
5 import java.util.TreeMap;
6 import java.util.logging.Level;
7 import java.util.logging.Logger;
9 import javax.naming.InitialContext;
10 import javax.naming.NamingException;
11 import javax.persistence.EntityManager;
12 import javax.persistence.EntityManagerFactory;
13 import javax.persistence.EntityTransaction;
14 import javax.persistence.Persistence;
15 import javax.sql.DataSource;
17 import org.wamblee.support.jndi.StubInitialContextFactory;
18 import org.wamblee.support.persistence.toplink.JndiSessionCustomizer;
22 * Utility for building an appropriately configured EntityManagerFactory. The
23 * idea is that a persistence.xml is used unchanged from the production version.
24 * This utility will then add the additional properties required for execution
25 * in a standalone environment.
27 * The other purpose is to to shield dependencies of the test code on a
28 * particular JPA provider.
30 public class JpaBuilder {
32 private static final Logger LOGGER = Logger.getLogger(JpaBuilder.class
36 * Callback interface to execute some JPA code within a transaction with the
37 * entitymanager to use provided as input.
39 public static interface JpaUnitOfWork<T> {
41 * Executes the unit of work. A transaction has been started.
42 * @param em Entity manager.
43 * @return Result of the execute method. If you don't want to return anything use
44 * <code>Void</code> for the return type and return null from the implementation.
46 T execute(EntityManager em);
49 private PersistenceUnitDescription persistenceUnit;
50 private DataSource dataSource;
51 private EntityManagerFactory factory;
54 * Constructs the builder.
57 * Datasource of database.
58 * @param aPersistenceUnit
61 public JpaBuilder(DataSource aDataSource,
62 PersistenceUnitDescription aPersistenceUnit) {
63 persistenceUnit = aPersistenceUnit;
64 dataSource = aDataSource;
65 StubInitialContextFactory.register();
69 * Starts the builder, which in particular, mocks JNDI, binds the datasource
70 * the JNDI where the persistence unit expects it, creates the entity
71 * manager factory, and forces creation of the database schema.
73 public void start() throws Exception {
75 InitialContext ctx = new InitialContext();
76 ctx.bind(persistenceUnit.getJndiName(), dataSource);
77 } catch (NamingException e) {
78 throw new RuntimeException("JNDI problem", e);
80 factory = createFactory();
81 execute(new JpaUnitOfWork<Void>() {
82 public Void execute(EntityManager em) {
83 // Empty, just to trigger database schema creation.
90 * Stops the entity manager factory and disables JNDI mocking.
93 StubInitialContextFactory.unregister();
98 * Creates a new entity manager factory. Typically not used by test code.
99 * @return Entity manager factory.
101 public EntityManagerFactory createFactory() {
102 Map<String, String> jpaProps = new TreeMap<String, String>();
103 jpaProps.put("toplink.session.customizer", JndiSessionCustomizer.class
105 jpaProps.put("toplink.ddl-generation", "create-tables");
106 return Persistence.createEntityManagerFactory(persistenceUnit
107 .getUnitName(), jpaProps);
111 * Executes a unit of work. This creates an entitymanager and runs the
112 * {@link JpaUnitOfWork#execute(EntityManager)} within a transaction, passing
113 * it the entity manager. Use of this method saves a lot of typing for applications.
115 * @param aWork Work to execute.
116 * @return The return value of the execute method of the unit of work.
118 public <T> T execute(JpaUnitOfWork<T> aWork) throws Exception {
119 EntityManager em = factory.createEntityManager();
120 EntityTransaction transaction = em.getTransaction();
123 T value = aWork.execute(em);
124 transaction.commit();
126 } catch (Exception e) {
127 LOGGER.log(Level.WARNING, "Exception occured", e);
128 transaction.rollback();