You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by gp...@apache.org on 2012/07/29 17:12:14 UTC
[6/6] git commit: DELTASPIKE-219
BeanManagedUserTransactionPersistenceStrategy (first draft)
DELTASPIKE-219 BeanManagedUserTransactionPersistenceStrategy (first draft)
Project: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/commit/c627f70e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/tree/c627f70e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/diff/c627f70e
Branch: refs/heads/master
Commit: c627f70eb73dff46c77b82b1562f3ea941bcb54c
Parents: 5a204ee
Author: gpetracek <gp...@apache.org>
Authored: Fri Jul 27 10:27:32 2012 +0200
Committer: gpetracek <gp...@apache.org>
Committed: Sun Jul 29 13:55:20 2012 +0200
----------------------------------------------------------------------
.../deltaspike/core/util/ExceptionUtils.java | 3 +-
deltaspike/modules/jpa/impl/pom.xml | 5 +
...nManagedUserTransactionPersistenceStrategy.java | 243 +++++++++++++++
.../ResourceLocalPersistenceStrategy.java | 25 +-
4 files changed, 265 insertions(+), 11 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/c627f70e/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/ExceptionUtils.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/ExceptionUtils.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/ExceptionUtils.java
index 9746dfd..40e18d5 100644
--- a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/ExceptionUtils.java
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/ExceptionUtils.java
@@ -30,10 +30,11 @@ public abstract class ExceptionUtils
// prevent instantiation
}
- public static void throwAsRuntimeException(Throwable throwable)
+ public static RuntimeException throwAsRuntimeException(Throwable throwable)
{
//Attention: helper which allows to use a trick to throw a cached checked exception without a wrapping exception
new ExceptionHelper<RuntimeException>().throwException(throwable);
+ return null; //not needed due to the helper trick, but it's easier for using it
}
public static void changeAndThrowException(Throwable throwable, String customMessage)
http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/c627f70e/deltaspike/modules/jpa/impl/pom.xml
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jpa/impl/pom.xml b/deltaspike/modules/jpa/impl/pom.xml
index 7852840..2457f14 100644
--- a/deltaspike/modules/jpa/impl/pom.xml
+++ b/deltaspike/modules/jpa/impl/pom.xml
@@ -46,6 +46,11 @@
<groupId>org.apache.deltaspike.modules</groupId>
<artifactId>deltaspike-jpa-module-api</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-jta_1.1_spec</artifactId>
+ </dependency>
</dependencies>
<build>
http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/c627f70e/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/BeanManagedUserTransactionPersistenceStrategy.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/BeanManagedUserTransactionPersistenceStrategy.java b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/BeanManagedUserTransactionPersistenceStrategy.java
new file mode 100644
index 0000000..19c1fe1
--- /dev/null
+++ b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/BeanManagedUserTransactionPersistenceStrategy.java
@@ -0,0 +1,243 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.jpa.impl.transaction;
+
+import org.apache.deltaspike.core.api.projectstage.ProjectStage;
+import org.apache.deltaspike.core.impl.util.JndiUtils;
+import org.apache.deltaspike.core.util.ExceptionUtils;
+
+import javax.enterprise.context.Dependent;
+import javax.enterprise.inject.Alternative;
+import javax.inject.Inject;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityTransaction;
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.UserTransaction;
+import java.util.logging.Logger;
+
+/**
+ * <p>{@link org.apache.deltaspike.jpa.spi.PersistenceStrategy} for using JTA (bean-managed-)transactions
+ * (including XA transactions with a XA DataSource).
+ * The basic features are identical to the {@link ResourceLocalPersistenceStrategy} (for
+ * persistent-unit-transaction-type 'RESOURCE_LOCAL' only).
+ * Also different transaction-types for different persistence-units are supported.</p>
+ *
+ * <p>It's possible to extend this class, if {@link org.apache.deltaspike.core.api.exclude.annotation.Exclude}
+ * needs to be used e.g. in case of a different dev- and production-environment
+ * (in combination with different {@link javax.persistence.EntityManagerFactory}s).</p>
+ */
+@Dependent
+@Alternative
+@SuppressWarnings("UnusedDeclaration")
+//TODO move to a separated ds-jta module and use @Specializes -> no additional config is needed
+public class BeanManagedUserTransactionPersistenceStrategy extends ResourceLocalPersistenceStrategy
+{
+ private static final long serialVersionUID = -2432802805095533499L;
+
+ private static final Logger LOGGER =
+ Logger.getLogger(BeanManagedUserTransactionPersistenceStrategy.class.getName());
+
+ private static final String USER_TRANSACTION_JNDI_NAME = "java:comp/UserTransaction";
+
+ @Inject
+ private ProjectStage projectStage;
+
+ @Override
+ protected EntityTransaction getTransaction(EntityManager entityManager)
+ {
+ return new UserTransactionAdapter(entityManager);
+ }
+
+ /**
+ * Needed because the {@link EntityManager} was created outside of the {@link UserTransaction}.
+ * Can't be in {@link BeanManagedUserTransactionPersistenceStrategy.UserTransactionAdapter#begin()}
+ * because {@link ResourceLocalPersistenceStrategy} needs to do
+ * <pre>
+ * if (!transaction.isActive())
+ * {
+ * transaction.begin();
+ * }
+ * </pre>
+ * for the {@link EntityTransaction} of every {@link EntityManager}
+ * and {@link BeanManagedUserTransactionPersistenceStrategy.UserTransactionAdapter#isActive()}
+ * can only use the status information of the {@link UserTransaction} and therefore
+ * {@link BeanManagedUserTransactionPersistenceStrategy.UserTransactionAdapter#begin()}
+ * will only executed once, but {@link javax.persistence.EntityManager#joinTransaction()}
+ * needs to be called for every {@link EntityManager}
+ *
+ * @param entityManager current entity-manager
+ */
+
+ /*
+ Hint: the alternative would be a ThreadLocal to store additional information which would require
+ a callback in ResourceLocalPersistenceStrategy for the cleanup of the ThreadLocal.
+ -> #prepareEntityManager is more solid.
+ */
+ @Override
+ protected void prepareEntityManager(EntityManager entityManager)
+ {
+ entityManager.joinTransaction();
+ }
+
+ private class UserTransactionAdapter implements EntityTransaction
+ {
+ private final UserTransaction userTransaction;
+ private final EntityManager entityManager;
+
+ public UserTransactionAdapter(EntityManager entityManager)
+ {
+ this.userTransaction = JndiUtils.lookup(USER_TRANSACTION_JNDI_NAME, UserTransaction.class);
+ this.entityManager = entityManager;
+ }
+
+ /**
+ * Only delegate to the {@link UserTransaction} if the state of the
+ * {@link UserTransaction} is {@link Status#STATUS_NO_TRANSACTION}
+ * (= the status before and after a started transaction).
+ */
+ @Override
+ public void begin()
+ {
+ try
+ {
+ //2nd check (already done by #isActive triggered by ResourceLocalPersistenceStrategy directly before)
+ //currently to filter STATUS_UNKNOWN - see to-do -> TODO re-visit it
+ if (this.userTransaction.getStatus() == Status.STATUS_NO_TRANSACTION)
+ {
+ this.userTransaction.begin();
+ }
+ }
+ catch (Exception e)
+ {
+ throw ExceptionUtils.throwAsRuntimeException(e);
+ }
+ }
+
+ /**
+ * Only delegate to the {@link UserTransaction} if the state of the
+ * {@link UserTransaction} is one of
+ * <ul>
+ * <li>{@link Status#STATUS_ACTIVE}</li>
+ * <li>{@link Status#STATUS_PREPARING}</li>
+ * <li>{@link Status#STATUS_PREPARED}</li>
+ * </ul>
+ */
+ @Override
+ public void commit()
+ {
+ try
+ {
+ if (isTransactionReadyToCommit())
+ {
+ this.userTransaction.commit();
+ }
+ }
+ catch (Exception e)
+ {
+ throw ExceptionUtils.throwAsRuntimeException(e);
+ }
+ }
+
+ /**
+ * Only delegate to the {@link UserTransaction} if the state of the
+ * {@link UserTransaction} is one of
+ * <ul>
+ * <li>{@link Status#STATUS_ACTIVE}</li>
+ * <li>{@link Status#STATUS_PREPARING}</li>
+ * <li>{@link Status#STATUS_PREPARED}</li>
+ * <li>{@link Status#STATUS_MARKED_ROLLBACK}</li>
+ * <li>{@link Status#STATUS_COMMITTING}</li>
+ * </ul>
+ */
+ @Override
+ public void rollback()
+ {
+ try
+ {
+ if (isTransactionAllowedToRollback())
+ {
+ this.userTransaction.rollback();
+ }
+ }
+ catch (SystemException e)
+ {
+ throw ExceptionUtils.throwAsRuntimeException(e);
+ }
+ }
+
+ @Override
+ public void setRollbackOnly()
+ {
+ try
+ {
+ this.userTransaction.setRollbackOnly();
+ }
+ catch (SystemException e)
+ {
+ throw ExceptionUtils.throwAsRuntimeException(e);
+ }
+ }
+
+ @Override
+ public boolean getRollbackOnly()
+ {
+ try
+ {
+ return this.userTransaction.getStatus() == Status.STATUS_MARKED_ROLLBACK;
+ }
+ catch (SystemException e)
+ {
+ throw ExceptionUtils.throwAsRuntimeException(e);
+ }
+ }
+
+ /**
+ * @return true if the transaction has been started and not ended
+ */
+ @Override
+ public boolean isActive()
+ {
+ //we can't use the status of the overall
+ try
+ {
+ return this.userTransaction.getStatus() != Status.STATUS_NO_TRANSACTION &&
+ this.userTransaction.getStatus() != Status.STATUS_UNKNOWN; //TODO re-visit it
+ }
+ catch (SystemException e)
+ {
+ throw ExceptionUtils.throwAsRuntimeException(e);
+ }
+ }
+
+ private boolean isTransactionAllowedToRollback() throws SystemException
+ {
+ return isTransactionReadyToCommit() ||
+ this.userTransaction.getStatus() == Status.STATUS_MARKED_ROLLBACK ||
+ this.userTransaction.getStatus() == Status.STATUS_COMMITTING;
+ }
+
+ private boolean isTransactionReadyToCommit() throws SystemException
+ {
+ return this.userTransaction.getStatus() == Status.STATUS_ACTIVE ||
+ this.userTransaction.getStatus() == Status.STATUS_PREPARING ||
+ this.userTransaction.getStatus() == Status.STATUS_PREPARED;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/c627f70e/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/ResourceLocalPersistenceStrategy.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/ResourceLocalPersistenceStrategy.java b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/ResourceLocalPersistenceStrategy.java
index dbeb66b..10a34e8 100644
--- a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/ResourceLocalPersistenceStrategy.java
+++ b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/ResourceLocalPersistenceStrategy.java
@@ -95,27 +95,27 @@ public class ResourceLocalPersistenceStrategy implements PersistenceStrategy
@SuppressWarnings("UnusedDeclaration")
int transactionLayer = transactionBeanStorage.incrementRefCounter();
- for (Class<? extends Annotation> emQualifier : emQualifiers)
- {
- EntityManager entityManager = resolveEntityManagerForQualifier(emQualifier);
-
- transactionBeanStorage.storeUsedEntityManager(emQualifier, entityManager);
-
- ems.add(entityManager);
- }
-
Exception firstException = null;
try
{
- for (EntityManager entityManager : ems)
+ for (Class<? extends Annotation> emQualifier : emQualifiers)
{
+ EntityManager entityManager = resolveEntityManagerForQualifier(emQualifier);
+
+ transactionBeanStorage.storeUsedEntityManager(emQualifier, entityManager);
+
+ ems.add(entityManager);
+
EntityTransaction transaction = getTransaction(entityManager);
if (!transaction.isActive())
{
transaction.begin();
}
+
+ //don't move it before EntityTransaction#begin() and invoke it in any case
+ prepareEntityManager(entityManager);
}
return invocationContext.proceed();
@@ -248,6 +248,11 @@ public class ResourceLocalPersistenceStrategy implements PersistenceStrategy
return entityManager.getTransaction();
}
+ protected void prepareEntityManager(EntityManager entityManager)
+ {
+ //override if needed
+ }
+
private EntityManager resolveEntityManagerForQualifier(Class<? extends Annotation> emQualifier)
{
Bean<EntityManager> entityManagerBean = resolveEntityManagerBean(emQualifier);