package rename for test libraries.
[utils] / test / enterprise / src / main / java / org / wamblee / test / persistence / JpaBuilder.java
diff --git a/test/enterprise/src/main/java/org/wamblee/test/persistence/JpaBuilder.java b/test/enterprise/src/main/java/org/wamblee/test/persistence/JpaBuilder.java
new file mode 100644 (file)
index 0000000..331ea9a
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2005-2010 the original author or authors.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.wamblee.test.persistence;
+
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityTransaction;
+import javax.persistence.Persistence;
+import javax.persistence.PersistenceException;
+
+import org.wamblee.test.jndi.StubInitialContextFactory;
+
+/**
+ * Utility for building an appropriately configured EntityManagerFactory. The
+ * idea is that a persistence.xml is used unchanged from the production version.
+ * This utility will then add the additional properties required for execution
+ * in a standalone environment.
+ * 
+ * The other purpose is to to shield dependencies of the test code on a
+ * particular JPA provider.
+ */
+public class JpaBuilder {
+
+    private static final Logger LOGGER = Logger.getLogger(JpaBuilder.class
+        .getName());
+
+    /**
+     * Callback interface to execute some JPA code within a transaction with the
+     * entitymanager to use provided as input.
+     */
+    public static interface JpaUnitOfWork<T> {
+        /**
+         * Executes the unit of work. A transaction has been started.
+         * 
+         * @param aEm
+         *            Entity manager.
+         * @return Result of the execute method. If you don't want to return
+         *         anything use <code>Void</code> for the return type and return
+         *         null from the implementation.
+         */
+        T execute(EntityManager aEm) throws Exception;
+    }
+
+    private PersistenceUnitDescription persistenceUnit;
+    private String url; 
+    private String user; 
+    private String password; 
+    private EntityManagerFactory factory;
+
+    /**
+     * Constructs the builder.
+     * 
+     * @param aUrl JDBC URL
+     * @param aUser User name
+     * @param aPassword Password.
+     * @param aPersistenceUnit
+     *            Persistence unit.
+     */
+    public JpaBuilder(String aUrl, String aUser, String aPassword,
+        PersistenceUnitDescription aPersistenceUnit) {
+        persistenceUnit = aPersistenceUnit;
+        url = aUrl; 
+        user = aUser; 
+        password = aPassword; 
+    }
+
+    /**
+     * Starts the builder, which in particular, mocks JNDI, binds the datasource
+     * the JNDI where the persistence unit expects it, creates the entity
+     * manager factory, and forces creation of the database schema.
+     */
+    public void start() throws Exception {
+        factory = createFactory();
+        try {
+            execute(new JpaUnitOfWork<Void>() {
+                public Void execute(EntityManager aEm) {
+                    // Empty, just to trigger database schema creation.
+                    return null;
+                }
+            });
+        } catch (PersistenceException e) {
+            factory.close();
+            throw e;
+        }
+    }
+
+    /**
+     * Stops the entity manager factory and disables JNDI mocking.
+     */
+    public void stop() {
+        StubInitialContextFactory.unregister();
+        factory.close();
+    }
+
+    /**
+     * Creates a new entity manager factory. Typically not used by test code.
+     * 
+     * @return Entity manager factory.
+     */
+    public EntityManagerFactory createFactory() {
+        Map<String, String> jpaProps = new TreeMap<String, String>();
+        
+        jpaProps.put("javax.persistence.jtaDataSource", null);
+        jpaProps.put("javax.persistence.transactionType", "RESOURCE_LOCAL");
+        jpaProps.put("javax.persistence.jdbc.url", url);
+        jpaProps.put("javax.persistence.jdbc.user", user);
+        jpaProps.put("javax.persistence.jdbc.password", password);
+
+        JpaCustomizerBuilder.getCustomizer().customize(persistenceUnit,
+            jpaProps);
+        
+        // jpaProps.put("javax.persistence.provider",
+        // HibernatePersistence.class.getName());
+        EntityManagerFactory emf = Persistence.createEntityManagerFactory(
+            persistenceUnit.getUnitName(), jpaProps);
+
+        LOGGER.info("Using " + emf.getClass());
+        return emf;
+    }
+
+    /**
+     * Executes a unit of work. This creates an entitymanager and runs the
+     * {@link JpaUnitOfWork#execute(EntityManager)} within a transaction,
+     * passing it the entity manager. Use of this method saves a lot of typing
+     * for applications.
+     * 
+     * @param aWork
+     *            Work to execute.
+     * @return The return value of the execute method of the unit of work.
+     */
+    public <T> T execute(JpaUnitOfWork<T> aWork) throws Exception {
+        EntityManager em = factory.createEntityManager();
+        EntityTransaction transaction = em.getTransaction();
+        transaction.begin();
+        try {
+            T value = aWork.execute(em);
+            transaction.commit();
+            return value;
+        } catch (Exception e) {
+            LOGGER.log(Level.WARNING, "Exception occured", e);
+            transaction.rollback();
+            throw e;
+        } finally {
+            em.close();
+        }
+    }
+}