import javax.persistence.Persistence;
import javax.persistence.PersistenceException;
+import org.wamblee.general.ThreadSpecificProxyFactory;
import org.wamblee.test.jndi.StubInitialContextFactory;
+import org.wamblee.test.transactions.TransactionResource;
+import org.wamblee.test.transactions.TransactionResult;
/**
* Utility for building an appropriately configured EntityManagerFactory. The
* The other purpose is to to shield dependencies of the test code on a
* particular JPA provider.
*/
-public class JpaBuilder {
+public class JpaBuilder implements TransactionResource<EntityManager> {
private static final Logger LOGGER = Logger.getLogger(JpaBuilder.class
.getName());
}
private PersistenceUnitDescription persistenceUnit;
- private String url;
- private String user;
- private String password;
+ private String url;
+ private String user;
+ private String password;
private EntityManagerFactory factory;
+ private ThreadSpecificProxyFactory<EntityManager> entityManager;
/**
* Constructs the builder.
*
- * @param aUrl JDBC URL
- * @param aUser User name
- * @param aPassword Password.
+ * @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;
+ url = aUrl;
+ user = aUser;
+ password = aPassword;
+ entityManager = new ThreadSpecificProxyFactory<EntityManager>(
+ EntityManager.class);
}
/**
*/
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);
JpaCustomizerBuilder.getCustomizer().customize(persistenceUnit,
jpaProps);
-
+
// jpaProps.put("javax.persistence.provider",
// HibernatePersistence.class.getName());
EntityManagerFactory emf = Persistence.createEntityManagerFactory(
* passing it the entity manager. Use of this method saves a lot of typing
* for applications.
*
+ * This method requires the transaction to succeed. Otherwise the test will
+ * fail. See {@link #execute(JpaUnitOfWork, TransactionResultCallback)} and
+ * {@link RequireTransactionStatus} for more possibilities.
+ *
* @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();
+ return execute(aWork, new RequireTransactionStatus(TransactionResult.COMMIT));
+ }
+
+ /**
+ * 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.
+ * @param aTransactionResultCallback
+ * callback to notify of the result of the transaction.
+ *
+ * @return The return value of the execute method of the unit of work.
+ */
+ public <T> T execute(JpaUnitOfWork<T> aWork,
+ TransactionResultCallback aCallback) throws Exception {
+ EntityManager em = begin();
try {
T value = aWork.execute(em);
- transaction.commit();
+ TransactionResult result = commit(em);
+ aCallback.status(result);
return value;
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Exception occured", e);
- transaction.rollback();
+ TransactionResult result = rollback(em);
+ aCallback.status(result);
throw e;
+ }
+ }
+
+ @Override
+ public EntityManager begin() {
+ EntityManager em = factory.createEntityManager();
+ EntityTransaction transaction = em.getTransaction();
+ transaction.begin();
+ entityManager.set(em);
+ return em;
+ }
+
+ @Override
+ public TransactionResult commit(EntityManager aEntityManager) {
+ try {
+ EntityTransaction transaction = aEntityManager.getTransaction();
+ if (transaction.isActive()) {
+ if (transaction.getRollbackOnly()) {
+ transaction.rollback();
+ return TransactionResult.ROLLBACK;
+ }
+ transaction.commit();
+ return TransactionResult.COMMIT;
+ }
+ return TransactionResult.UNKNOWN;
} finally {
- em.close();
+ aEntityManager.close();
+ entityManager.set(null);
}
}
+
+ @Override
+ public TransactionResult rollback(EntityManager aEntityManager) {
+ try {
+ EntityTransaction transaction = aEntityManager.getTransaction();
+ if (transaction.isActive()) {
+ transaction.rollback();
+ return TransactionResult.ROLLBACK;
+ }
+ return TransactionResult.UNKNOWN;
+ } finally {
+ if (aEntityManager.isOpen()) {
+ aEntityManager.close();
+ }
+ entityManager.set(null);
+ }
+ }
+
+ /**
+ * Gets a contextual reference to an entity manager that delegates to the
+ * appropriate (current) one which is active for the current transaction.
+ *
+ * @return EntityManager.
+ */
+ public EntityManager getContextualEntityManager() {
+ return entityManager.getProxy();
+ }
}