(no commit message)
[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.persistence.EntityManager;
24 import javax.persistence.EntityManagerFactory;
25 import javax.persistence.EntityTransaction;
26 import javax.persistence.Persistence;
27 import javax.persistence.PersistenceException;
28
29 import org.wamblee.support.jndi.StubInitialContextFactory;
30
31 /**
32  * Utility for building an appropriately configured EntityManagerFactory. The
33  * idea is that a persistence.xml is used unchanged from the production version.
34  * This utility will then add the additional properties required for execution
35  * in a standalone environment.
36  * 
37  * The other purpose is to to shield dependencies of the test code on a
38  * particular JPA provider.
39  */
40 public class JpaBuilder {
41
42     private static final Logger LOGGER = Logger.getLogger(JpaBuilder.class
43         .getName());
44
45     /**
46      * Callback interface to execute some JPA code within a transaction with the
47      * entitymanager to use provided as input.
48      */
49     public static interface JpaUnitOfWork<T> {
50         /**
51          * Executes the unit of work. A transaction has been started.
52          * 
53          * @param aEm
54          *            Entity manager.
55          * @return Result of the execute method. If you don't want to return
56          *         anything use <code>Void</code> for the return type and return
57          *         null from the implementation.
58          */
59         T execute(EntityManager aEm) throws Exception;
60     }
61
62     private PersistenceUnitDescription persistenceUnit;
63     private String url; 
64     private String user; 
65     private String password; 
66     private EntityManagerFactory factory;
67
68     /**
69      * Constructs the builder.
70      * 
71      * @param aUrl JDBC URL
72      * @param aUser User name
73      * @param aPassword Password.
74      * @param aPersistenceUnit
75      *            Persistence unit.
76      */
77     public JpaBuilder(String aUrl, String aUser, String aPassword,
78         PersistenceUnitDescription aPersistenceUnit) {
79         persistenceUnit = aPersistenceUnit;
80         url = aUrl; 
81         user = aUser; 
82         password = aPassword; 
83     }
84
85     /**
86      * Starts the builder, which in particular, mocks JNDI, binds the datasource
87      * the JNDI where the persistence unit expects it, creates the entity
88      * manager factory, and forces creation of the database schema.
89      */
90     public void start() throws Exception {
91         factory = createFactory();
92         try {
93             execute(new JpaUnitOfWork<Void>() {
94                 public Void execute(EntityManager aEm) {
95                     // Empty, just to trigger database schema creation.
96                     return null;
97                 }
98             });
99         } catch (PersistenceException e) {
100             factory.close();
101             throw e;
102         }
103     }
104
105     /**
106      * Stops the entity manager factory and disables JNDI mocking.
107      */
108     public void stop() {
109         StubInitialContextFactory.unregister();
110         factory.close();
111     }
112
113     /**
114      * Creates a new entity manager factory. Typically not used by test code.
115      * 
116      * @return Entity manager factory.
117      */
118     public EntityManagerFactory createFactory() {
119         Map<String, String> jpaProps = new TreeMap<String, String>();
120         
121         jpaProps.put("javax.persistence.jtaDataSource", null);
122         jpaProps.put("javax.persistence.transactionType", "RESOURCE_LOCAL");
123         jpaProps.put("javax.persistence.jdbc.url", url);
124         jpaProps.put("javax.persistence.jdbc.user", user);
125         jpaProps.put("javax.persistence.jdbc.password", password);
126
127         JpaCustomizerBuilder.getCustomizer().customize(persistenceUnit,
128             jpaProps);
129         
130         // jpaProps.put("javax.persistence.provider",
131         // HibernatePersistence.class.getName());
132         EntityManagerFactory emf = Persistence.createEntityManagerFactory(
133             persistenceUnit.getUnitName(), jpaProps);
134
135         LOGGER.info("Using " + emf.getClass());
136         return emf;
137     }
138
139     /**
140      * Executes a unit of work. This creates an entitymanager and runs the
141      * {@link JpaUnitOfWork#execute(EntityManager)} within a transaction,
142      * passing it the entity manager. Use of this method saves a lot of typing
143      * for applications.
144      * 
145      * @param aWork
146      *            Work to execute.
147      * @return The return value of the execute method of the unit of work.
148      */
149     public <T> T execute(JpaUnitOfWork<T> aWork) throws Exception {
150         EntityManager em = factory.createEntityManager();
151         EntityTransaction transaction = em.getTransaction();
152         transaction.begin();
153         try {
154             T value = aWork.execute(em);
155             transaction.commit();
156             return value;
157         } catch (Exception e) {
158             LOGGER.log(Level.WARNING, "Exception occured", e);
159             transaction.rollback();
160             throw e;
161         } finally {
162             em.close();
163         }
164     }
165 }