4d1921f5abf5a7c8f7d06d5bbd0f1824f4f96b02
[utils] / test / enterprise / src / main / java / org / wamblee / support / persistence / JpaBuilder.java
1 /*
2  * Copyright 2005-2010 the original author or authors.
3  * 
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
7  * 
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * 
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.
15  */ 
16 package org.wamblee.support.persistence;
17
18 import java.util.Map;
19 import java.util.TreeMap;
20 import java.util.logging.Level;
21 import java.util.logging.Logger;
22
23 import javax.naming.InitialContext;
24 import javax.naming.NamingException;
25 import javax.persistence.EntityManager;
26 import javax.persistence.EntityManagerFactory;
27 import javax.persistence.EntityTransaction;
28 import javax.persistence.Persistence;
29 import javax.sql.DataSource;
30
31 import org.wamblee.support.jndi.StubInitialContextFactory;
32
33 /**
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.
38  * 
39  * The other purpose is to to shield dependencies of the test code on a
40  * particular JPA provider.
41  */
42 public class JpaBuilder {
43
44     private static final Logger LOGGER = Logger.getLogger(JpaBuilder.class
45         .getName());
46
47     /**
48      * Callback interface to execute some JPA code within a transaction with the
49      * entitymanager to use provided as input.
50      */
51     public static interface JpaUnitOfWork<T> {
52         /**
53          * Executes the unit of work. A transaction has been started.
54          * 
55          * @param aEm
56          *            Entity manager.
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.
60          */
61         T execute(EntityManager aEm) throws Exception;
62     }
63
64     private PersistenceUnitDescription persistenceUnit;
65     private DataSource dataSource;
66     private EntityManagerFactory factory;
67
68     /**
69      * Constructs the builder.
70      * 
71      * @param aDataSource
72      *            Datasource of database.
73      * @param aPersistenceUnit
74      *            Persistence unit.
75      */
76     public JpaBuilder(DataSource aDataSource,
77         PersistenceUnitDescription aPersistenceUnit) {
78         persistenceUnit = aPersistenceUnit;
79         dataSource = aDataSource;
80         StubInitialContextFactory.register();
81     }
82
83     /**
84      * Starts the builder, which in particular, mocks JNDI, binds the datasource
85      * the JNDI where the persistence unit expects it, creates the entity
86      * manager factory, and forces creation of the database schema.
87      */
88     public void start() throws Exception {
89         try {
90             InitialContext ctx = new InitialContext();
91             ctx.bind(persistenceUnit.getJndiName(), dataSource);
92         } catch (NamingException e) {
93             throw new RuntimeException("JNDI problem", e);
94         }
95         factory = createFactory();
96         execute(new JpaUnitOfWork<Void>() {
97             public Void execute(EntityManager aEm) {
98                 // Empty, just to trigger database schema creation.
99                 return null;
100             }
101         });
102     }
103
104     /**
105      * Stops the entity manager factory and disables JNDI mocking.
106      */
107     public void stop() {
108         StubInitialContextFactory.unregister();
109         factory.close();
110     }
111
112     /**
113      * Creates a new entity manager factory. Typically not used by test code.
114      * 
115      * @return Entity manager factory.
116      */
117     public EntityManagerFactory createFactory() {
118         Map<String, String> jpaProps = new TreeMap<String, String>();
119
120         JpaCustomizerBuilder.getCustomizer().customize(persistenceUnit,
121             jpaProps);
122
123         // jpaProps.put("javax.persistence.provider",
124         // HibernatePersistence.class.getName());
125         EntityManagerFactory factory = Persistence.createEntityManagerFactory(
126             persistenceUnit.getUnitName(), jpaProps);
127
128         LOGGER.info("Using " + factory.getClass());
129         return factory;
130     }
131
132     /**
133      * Executes a unit of work. This creates an entitymanager and runs the
134      * {@link JpaUnitOfWork#execute(EntityManager)} within a transaction,
135      * passing it the entity manager. Use of this method saves a lot of typing
136      * for applications.
137      * 
138      * @param aWork
139      *            Work to execute.
140      * @return The return value of the execute method of the unit of work.
141      */
142     public <T> T execute(JpaUnitOfWork<T> aWork) throws Exception {
143         EntityManager em = factory.createEntityManager();
144         EntityTransaction transaction = em.getTransaction();
145         transaction.begin();
146         try {
147             T value = aWork.execute(em);
148             transaction.commit();
149             return value;
150         } catch (Exception e) {
151             LOGGER.log(Level.WARNING, "Exception occured", e);
152             transaction.rollback();
153             throw e;
154         } finally {
155             em.close();
156         }
157     }
158 }