8b6e339935f01206ee3f795e16a8df4be49beeed
[utils] /
1 package org.wamblee.support.persistence;
2
3 import java.util.Map;
4 import java.util.TreeMap;
5 import java.util.logging.Level;
6 import java.util.logging.Logger;
7
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;
15
16 import org.wamblee.support.jndi.StubInitialContextFactory;
17
18
19 /**
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.
24  * 
25  * The other purpose is to to shield dependencies of the test code on a
26  * particular JPA provider.
27  */
28 public class JpaBuilder {
29
30         private static final Logger LOGGER = Logger.getLogger(JpaBuilder.class
31                         .getName());
32
33         /**
34          * Callback interface to execute some JPA code within a transaction with the
35          * entitymanager to use provided as input.
36          */
37         public static interface JpaUnitOfWork<T> {
38                 /**
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. 
43                  */
44                 T execute(EntityManager em);
45         }
46
47         private PersistenceUnitDescription persistenceUnit;
48         private DataSource dataSource;
49         private EntityManagerFactory factory;
50
51         /**
52          * Constructs the builder.
53          * 
54          * @param aDataSource
55          *            Datasource of database.
56          * @param aPersistenceUnit
57          *            Persistence unit.
58          */
59         public JpaBuilder(DataSource aDataSource,
60                         PersistenceUnitDescription aPersistenceUnit) {
61                 persistenceUnit = aPersistenceUnit;
62                 dataSource = aDataSource;
63                 StubInitialContextFactory.register();
64         }
65
66         /**
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.
70          */
71         public void start() throws Exception {
72                 try {
73                         InitialContext ctx = new InitialContext();
74                         ctx.bind(persistenceUnit.getJndiName(), dataSource);
75                 } catch (NamingException e) {
76                         throw new RuntimeException("JNDI problem", e);
77                 }
78                 factory = createFactory();
79                 execute(new JpaUnitOfWork<Void>() {
80                         public Void execute(EntityManager em) {
81                                 // Empty, just to trigger database schema creation.
82                                 return null;
83                         }
84                 });
85         }
86
87         /**
88          * Stops the entity manager factory and disables JNDI mocking. 
89          */
90         public void stop() {
91                 StubInitialContextFactory.unregister();
92                 factory.close();
93         }
94
95         /**
96          * Creates a new entity manager factory. Typically not used by test code. 
97          * @return Entity manager factory. 
98          */
99         public EntityManagerFactory createFactory() {
100                 Map<String, String> jpaProps = new TreeMap<String, String>();
101         
102                 JpaCustomizerBuilder.getCustomizer().customize(persistenceUnit, jpaProps);
103                 
104                 //jpaProps.put("javax.persistence.provider", HibernatePersistence.class.getName());
105                 EntityManagerFactory factory = Persistence.createEntityManagerFactory(persistenceUnit
106                                 .getUnitName(), jpaProps);
107                 
108                 LOGGER.info("Using " + factory.getClass());
109                 return factory;
110         }
111
112         /**
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. 
116          * 
117          * @param aWork Work to execute. 
118          * @return The return value of the execute method of the unit of work. 
119          */
120         public <T> T execute(JpaUnitOfWork<T> aWork) throws Exception {
121                 EntityManager em = factory.createEntityManager();
122                 EntityTransaction transaction = em.getTransaction();
123                 transaction.begin();
124                 try {
125                         T value = aWork.execute(em);
126                         transaction.commit();
127                         return value; 
128                 } catch (Exception e) {
129                         LOGGER.log(Level.WARNING, "Exception occured", e);
130                         transaction.rollback();
131                         throw e; 
132                 } finally {
133                         em.close();
134                 }
135         }
136 }