You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by st...@apache.org on 2012/06/05 18:15:23 UTC

[1/4] git commit: DELTASPIKE-185 DELTASPIKE-175 @Transactional interceptor cleanup

Updated Branches:
  refs/heads/master 4b81872a0 -> 94327565d


DELTASPIKE-185 DELTASPIKE-175 @Transactional interceptor cleanup

This commit simplifies the whole structure and removes the handling
of @PersistenceContext. We must not touch those as this would leed
to Exceptions on EE servers.


Project: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/commit/94327565
Tree: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/tree/94327565
Diff: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/diff/94327565

Branch: refs/heads/master
Commit: 94327565d2c558185b71473a14786e11dc26c0b6
Parents: 88c4b00
Author: Mark Struberg <st...@apache.org>
Authored: Tue Jun 5 18:05:56 2012 +0200
Committer: Mark Struberg <st...@apache.org>
Committed: Tue Jun 5 18:05:56 2012 +0200

----------------------------------------------------------------------
 .../deltaspike/jpa/spi/PersistenceStrategy.java    |    2 +-
 .../deltaspike/jpa/impl/EntityManagerRef.java      |   95 ----
 .../jpa/impl/EntityManagerRefHolder.java           |   40 --
 .../jpa/impl/PersistenceContextMetaEntry.java      |   47 --
 .../deltaspike/jpa/impl/PersistenceHelper.java     |  198 --------
 .../transaction/InternalTransactionContext.java    |   98 ----
 .../PersistenceStrategyCleanupTestEvent.java       |   23 -
 .../transaction/PersistenceStrategyHelper.java     |  188 ++++++++
 .../TransactionBeanStorageCleanupTestEvent.java    |   23 -
 .../impl/transaction/TransactionMetaDataEntry.java |   73 ---
 .../impl/transaction/TransactionalInterceptor.java |    3 +
 .../TransactionalInterceptorStrategy.java          |  368 ++++-----------
 .../transaction/context/TransactionBeanEntry.java  |   13 -
 .../context/TransactionBeanStorage.java            |  262 +++++------
 .../transaction/context/TransactionContext.java    |  159 ++-----
 .../test/jpa/api/shared/TestEventObserver.java     |   54 ---
 .../DefaultEntityManagerInjectionTest.java         |   10 -
 .../DefaultNestedTransactionTest.java              |    7 -
 ...NestedMultiTransactionCatchedExceptionTest.java |    6 -
 .../NestedTransactionCatchedExceptionTest.java     |    6 -
 ...tityManagerInjectionUncatchedExceptionTest.java |    6 -
 ...anagerInjectionUncatchedFlushExceptionTest.java |    6 -
 ...ultiTransactionUncatchedFlushExceptionTest.java |    6 -
 ...stedMultiTransactionUncatchedExceptionTest.java |    6 -
 .../nested/NestedTransactionWithExceptionTest.java |    6 -
 .../auto/MultipleEntityManagerInjectionTest.java   |    6 -
 .../manual/ManualTransactionTest.java              |    7 -
 .../nested/NestedMultiTransactionTest.java         |    6 -
 .../nested/NestedTransactionTest.java              |    6 -
 .../stereotype/StereotypeTransactionalTest.java    |    7 -
 .../transactionhelper/TransactionHelperTest.java   |  116 +++++
 .../TransactionScopedEntityManagerProducer.java    |   30 ++
 ...ransactionScopedEntityManagerInjectionTest.java |   12 -
 ...aultTransactionScopedNestedTransactionTest.java |    6 -
 ...ransactionScopedEntityManagerInjectionTest.java |    6 -
 .../ManualTransactionScopedTransactionTest.java    |    7 -
 ...estedMultiTransactionScopedTransactionTest.java |    6 -
 .../NestedTransactionScopedTransactionTest.java    |    6 -
 ...ereotypeTransactionScopedTransactionalTest.java |    6 -
 39 files changed, 583 insertions(+), 1349 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/94327565/deltaspike/modules/jpa/api/src/main/java/org/apache/deltaspike/jpa/spi/PersistenceStrategy.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jpa/api/src/main/java/org/apache/deltaspike/jpa/spi/PersistenceStrategy.java b/deltaspike/modules/jpa/api/src/main/java/org/apache/deltaspike/jpa/spi/PersistenceStrategy.java
index a5d49e4..49916ab 100644
--- a/deltaspike/modules/jpa/api/src/main/java/org/apache/deltaspike/jpa/spi/PersistenceStrategy.java
+++ b/deltaspike/modules/jpa/api/src/main/java/org/apache/deltaspike/jpa/spi/PersistenceStrategy.java
@@ -21,7 +21,7 @@ package org.apache.deltaspike.jpa.spi;
 import org.apache.deltaspike.core.spi.InterceptorStrategy;
 
 /**
- * Marker interface for a pluggable strategy for {@link org.apache.deltaspike.jpa.api.Transactional}
+ * Marker interface for a plugable strategy for {@link org.apache.deltaspike.jpa.api.Transactional}.
  */
 public interface PersistenceStrategy extends InterceptorStrategy
 {

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/94327565/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/EntityManagerRef.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/EntityManagerRef.java b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/EntityManagerRef.java
deleted file mode 100644
index 8c0d349..0000000
--- a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/EntityManagerRef.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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;
-
-import javax.persistence.EntityManager;
-import java.io.Serializable;
-import java.lang.reflect.Field;
-
-/**
- * Serializable entry which stores information about an {@link javax.persistence.EntityManager}
- */
-public class EntityManagerRef implements Serializable
-{
-    private static final long serialVersionUID = -4273544531446327680L;
-
-    private String key;
-
-    private final Class sourceClass;
-    private final String fieldName;
-
-    private transient Field entityManagerField;
-
-    EntityManagerRef(Class sourceClass, String fieldName, String key)
-    {
-        this.sourceClass = sourceClass;
-        this.fieldName = fieldName;
-        this.key = key;
-    }
-
-    public String getKey()
-    {
-        return key;
-    }
-
-    public Class getSourceClass()
-    {
-        return sourceClass;
-    }
-
-    public String getFieldName()
-    {
-        return fieldName;
-    }
-
-    //we can't cache the reference,
-    //because this instance will be stored in a cache and we have to support dependent scoped entity managers
-    public EntityManager getEntityManager(Object target)
-    {
-        if (this.entityManagerField == null)
-        {
-            try
-            {
-                this.entityManagerField = this.sourceClass.getDeclaredField(this.fieldName);
-            }
-            catch (NoSuchFieldException e)
-            {
-                //TODO add logging in case of project stage dev.
-                return null;
-            }
-        }
-
-        if (!entityManagerField.isAccessible())
-        {
-            entityManagerField.setAccessible(true);
-        }
-
-        try
-        {
-            @SuppressWarnings({ "UnnecessaryLocalVariable" })
-            EntityManager entityManager = (EntityManager) entityManagerField.get(target);
-            return entityManager;
-        }
-        catch (IllegalAccessException e)
-        {
-            //TODO add logging in case of project stage dev.
-            return null;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/94327565/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/EntityManagerRefHolder.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/EntityManagerRefHolder.java b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/EntityManagerRefHolder.java
deleted file mode 100644
index 00dbe34..0000000
--- a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/EntityManagerRefHolder.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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;
-
-import java.util.List;
-
-//TODO refactor it to remove this workaround
-class EntityManagerRefHolder extends EntityManagerRef
-{
-    private static final long serialVersionUID = -7002376898682639768L;
-
-    private List<EntityManagerRef> entityManagerRefs;
-
-    EntityManagerRefHolder(List<EntityManagerRef> entityManagerRefs)
-    {
-        super(null, null, null);
-        this.entityManagerRefs = entityManagerRefs;
-    }
-
-    List<EntityManagerRef> getEntityManagerRefs()
-    {
-        return entityManagerRefs;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/94327565/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/PersistenceContextMetaEntry.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/PersistenceContextMetaEntry.java b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/PersistenceContextMetaEntry.java
deleted file mode 100644
index b2d7170..0000000
--- a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/PersistenceContextMetaEntry.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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;
-
-/**
- * Entry which stores information about a {@link javax.persistence.PersistenceContext}
- */
-class PersistenceContextMetaEntry extends EntityManagerRef
-{
-    private static final long serialVersionUID = 637184416580955956L;
-
-    private String unitName;
-    private boolean extended;
-
-    PersistenceContextMetaEntry(Class sourceClass, String fieldName, String unitName, boolean extended)
-    {
-        super(sourceClass, fieldName, unitName);
-        this.unitName = unitName;
-        this.extended = extended;
-    }
-
-    String getUnitName()
-    {
-        return unitName;
-    }
-
-    boolean isExtended()
-    {
-        return extended;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/94327565/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/PersistenceHelper.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/PersistenceHelper.java b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/PersistenceHelper.java
deleted file mode 100644
index f4561ad..0000000
--- a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/PersistenceHelper.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * 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;
-
-import org.apache.deltaspike.core.api.provider.BeanManagerProvider;
-import org.apache.deltaspike.core.util.ClassUtils;
-
-import javax.enterprise.inject.Default;
-import javax.enterprise.inject.Typed;
-import javax.enterprise.inject.spi.BeanManager;
-import javax.persistence.EntityManager;
-import javax.persistence.PersistenceContext;
-import javax.persistence.PersistenceContextType;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Helper which provides util methods for
- * {@link org.apache.deltaspike.jpa.impl.transaction.TransactionalInterceptorStrategy}
- */
-@Typed()
-public class PersistenceHelper
-{
-    private static final String NO_FIELD_MARKER = PersistenceHelper.class.getName() + ":DEFAULT_FIELD";
-
-    private static transient volatile Map<ClassLoader, Map<String, EntityManagerRef>> persistenceContextMetaEntries =
-        new ConcurrentHashMap<ClassLoader, Map<String, EntityManagerRef>>();
-
-    private PersistenceHelper()
-    {
-        //prevent instantiation
-    }
-
-    /**
-     * Analyzes the given instance and returns the found reference to an injected {@link EntityManager}
-     * or null otherwise
-     *
-     * @param target instance to analyze
-     * @return the injected entity-manager or null otherwise
-     */
-    public static List<EntityManagerRef> tryToFindEntityManagerReference(Object target)
-    {
-        List<EntityManagerRef> entityManagers = tryToFindEntityManagerEntryInTarget(target);
-
-        if (entityManagers == null || entityManagers.isEmpty())
-        {
-            return null;
-        }
-        return entityManagers;
-    }
-
-    /*
-     * needed for special add-ons - don't change it!
-     */
-    static List<EntityManagerRef> tryToFindEntityManagerEntryInTarget(Object target)
-    {
-        Map<String, EntityManagerRef> mapping = persistenceContextMetaEntries.get(getClassLoader());
-
-        mapping = initMapping(mapping);
-
-        String key = target.getClass().getName();
-        EntityManagerRef entityManagerRef = mapping.get(key);
-
-        if (entityManagerRef != null && entityManagerRef instanceof PersistenceContextMetaEntry &&
-                NO_FIELD_MARKER.equals(entityManagerRef.getFieldName()))
-        {
-            return null;
-        }
-
-        if (entityManagerRef == null)
-        {
-            List<EntityManagerRef> foundEntries = findEntityManagerMetaReferences(target.getClass());
-
-            if (foundEntries.isEmpty())
-            {
-                mapping.put(key, new PersistenceContextMetaEntry(
-                        Object.class, NO_FIELD_MARKER, Default.class.getName(), false));
-                return null;
-            }
-
-            if (foundEntries.size() == 1)
-            {
-                entityManagerRef = foundEntries.iterator().next();
-            }
-            else
-            {
-                //TODO remove workaround
-                entityManagerRef = new EntityManagerRefHolder(foundEntries);
-            }
-            mapping.put(key, entityManagerRef);
-        }
-
-        List<EntityManagerRef> result = new ArrayList<EntityManagerRef>();
-
-        if (entityManagerRef instanceof EntityManagerRefHolder)
-        {
-            for (EntityManagerRef currentRef : ((EntityManagerRefHolder) entityManagerRef).getEntityManagerRefs())
-            {
-                result.add(currentRef);
-            }
-        }
-        else
-        {
-            result.add(entityManagerRef);
-        }
-        return result;
-    }
-
-    private static synchronized Map<String, EntityManagerRef> initMapping(
-            Map<String, EntityManagerRef> mapping)
-    {
-        if (mapping == null)
-        {
-            mapping = new ConcurrentHashMap<String, EntityManagerRef>();
-            persistenceContextMetaEntries.put(getClassLoader(), mapping);
-        }
-        return mapping;
-    }
-
-    private static List<EntityManagerRef> findEntityManagerMetaReferences(Class target)
-    {
-        List<EntityManagerRef> result = new ArrayList<EntityManagerRef>();
-
-        BeanManager beanManager = BeanManagerProvider.getInstance().getBeanManager();
-
-        //TODO support other injection types
-        Class currentParamClass = target;
-        PersistenceContext persistenceContext;
-        while (currentParamClass != null && !Object.class.getName().equals(currentParamClass.getName()))
-        {
-            //TODO scan methods to support a manual lookup
-
-            for (Field currentField : currentParamClass.getDeclaredFields())
-            {
-                persistenceContext = currentField.getAnnotation(PersistenceContext.class);
-                if (persistenceContext != null)
-                {
-                    result.add(new PersistenceContextMetaEntry(
-                            currentParamClass,
-                            currentField.getName(),
-                            persistenceContext.unitName(),
-                            PersistenceContextType.EXTENDED.equals(persistenceContext.type())));
-                    continue;
-                }
-
-                if (EntityManager.class.isAssignableFrom(currentField.getType()))
-                {
-                    String key = createKey(currentField, beanManager);
-                    //TODO discuss support of extended entity-managers
-                    result.add(new EntityManagerRef(currentParamClass, currentField.getName(), key));
-                }
-            }
-            currentParamClass = currentParamClass.getSuperclass();
-        }
-
-        return result;
-    }
-
-    private static String createKey(Field entityManagerField, BeanManager beanManager)
-    {
-        for (Annotation annotation : entityManagerField.getAnnotations())
-        {
-            if (beanManager.isQualifier(annotation.annotationType()))
-            {
-                //TODO add values of binding annotation-members
-                //for now it's ok because we haven't allowed binding qualifier values here
-                return annotation.annotationType().getName();
-            }
-        }
-
-        return Default.class.getName();
-    }
-
-    private static ClassLoader getClassLoader()
-    {
-        return ClassUtils.getClassLoader(null);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/94327565/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/InternalTransactionContext.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/InternalTransactionContext.java b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/InternalTransactionContext.java
deleted file mode 100644
index 3634362..0000000
--- a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/InternalTransactionContext.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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.literal.AnyLiteral;
-
-import javax.enterprise.inject.spi.Bean;
-import javax.enterprise.inject.spi.BeanManager;
-import javax.persistence.EntityManager;
-import java.lang.annotation.Annotation;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-class InternalTransactionContext
-{
-    private final BeanManager beanManager;
-
-    private Map<String, TransactionMetaDataEntry> transactionMetaDataEntries
-        = new HashMap<String, TransactionMetaDataEntry>();
-
-    InternalTransactionContext(BeanManager beanManager)
-    {
-        this.beanManager = beanManager;
-    }
-
-    void addTransactionMetaDataEntry(String key, EntityManager entityManager)
-    {
-        if (!this.transactionMetaDataEntries.containsKey(key))
-        {
-            this.transactionMetaDataEntries.put(key, new TransactionMetaDataEntry(key, entityManager));
-        }
-    }
-
-    void addTransactionMetaDataEntry(Class<? extends Annotation> qualifier)
-    {
-        addTransactionMetaDataEntry(qualifier.getName(), resolveEntityManagerForQualifier(qualifier));
-    }
-
-    Collection<TransactionMetaDataEntry> getTransactionMetaDataEntries()
-    {
-        return transactionMetaDataEntries.values();
-    }
-
-    private EntityManager resolveEntityManagerForQualifier(Class<? extends Annotation> qualifierClass)
-    {
-        Bean<EntityManager> entityManagerBean = resolveEntityManagerBean(qualifierClass);
-
-        if (entityManagerBean == null)
-        {
-            return null;
-        }
-
-        return (EntityManager) beanManager.getReference(entityManagerBean, EntityManager.class,
-                beanManager.createCreationalContext(entityManagerBean));
-    }
-
-    protected Bean<EntityManager> resolveEntityManagerBean(Class<? extends Annotation> qualifierClass)
-    {
-        Set<Bean<?>> entityManagerBeans = beanManager.getBeans(EntityManager.class, new AnyLiteral());
-        if (entityManagerBeans == null)
-        {
-            entityManagerBeans = new HashSet<Bean<?>>();
-        }
-
-        for (Bean<?> currentEntityManagerBean : entityManagerBeans)
-        {
-            Set<Annotation> foundQualifierAnnotations = currentEntityManagerBean.getQualifiers();
-
-            for (Annotation currentQualifierAnnotation : foundQualifierAnnotations)
-            {
-                if (currentQualifierAnnotation.annotationType().equals(qualifierClass))
-                {
-                    return (Bean<EntityManager>) currentEntityManagerBean;
-                }
-            }
-        }
-        return null;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/94327565/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/PersistenceStrategyCleanupTestEvent.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/PersistenceStrategyCleanupTestEvent.java b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/PersistenceStrategyCleanupTestEvent.java
deleted file mode 100644
index b255199..0000000
--- a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/PersistenceStrategyCleanupTestEvent.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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;
-
-public class PersistenceStrategyCleanupTestEvent
-{
-}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/94327565/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/PersistenceStrategyHelper.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/PersistenceStrategyHelper.java b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/PersistenceStrategyHelper.java
new file mode 100644
index 0000000..8a641bc
--- /dev/null
+++ b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/PersistenceStrategyHelper.java
@@ -0,0 +1,188 @@
+/*
+ * 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.jpa.api.Transactional;
+
+import javax.enterprise.context.Dependent;
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Default;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.inject.Inject;
+import javax.interceptor.InvocationContext;
+import javax.persistence.EntityManager;
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Helper which provides utility methods for any
+ * {@link org.apache.deltaspike.jpa.spi.PersistenceStrategy}.
+ */
+@Dependent
+public class PersistenceStrategyHelper implements Serializable
+{
+    @Inject
+    private BeanManager beanManager;
+
+    /**
+     * <p>This method uses the InvocationContext to scan the &#064;Transactional
+     * interceptor for a manually specified Qualifier.</p>
+     *
+     * <p>If none is given (defaults to &#04;Any.class) then we scan the intercepted
+     * instance and resolve the Qualifiers of all it's injected EntityManagers.</p>
+     *
+     * <p>Please note that we will only pickup the first Qualifier on the
+     * injected EntityManager. We also do <b>not</b> parse for binding or
+     * &h#064;NonBinding values. A &#064;Qualifier should not have any parameter at all.</p>
+     * @param transactionalAnnotation the &#064;Transactional annotation found on the intercepted class
+     * @param interceptedTargetClass the Class of the intercepted target
+     */
+    public Set<Class<? extends Annotation>> resolveEntityManagerQualifiers(Transactional transactionalAnnotation,
+                                                                           Class interceptedTargetClass)
+    {
+        HashSet<Class<? extends Annotation>> emQualifiers;
+
+
+        Class<? extends Annotation>[] qualifierClasses = transactionalAnnotation.qualifier();
+
+        if (qualifierClasses.length == 1 && Any.class.equals(qualifierClasses[0]) )
+        {
+            // this means we have no special EntityManager configured in the interceptor
+            // thus we should scan all the EntityManagers ourselfs from the intercepted class
+            emQualifiers = new HashSet<Class<? extends Annotation>>();
+            collectEntityManagerQualifiersOnClass(emQualifiers, interceptedTargetClass);
+        }
+        else
+        {
+            // take the qualifierKeys from the qualifierClasses
+            emQualifiers = new HashSet<Class<? extends Annotation>>();
+            for (Class<? extends Annotation> qualifier : qualifierClasses)
+            {
+                emQualifiers.add(qualifier);
+            }
+        }
+
+        return emQualifiers;
+    }
+
+    /**
+     * Scan the given class and return all the injected EntityManager fields.
+     * <p>Attention: we do only pick up EntityManagers which use &#064;Inject!</p>
+     */
+    private void collectEntityManagerQualifiersOnClass(Set<Class<? extends Annotation>> emQualifiers,Class target)
+    {
+        // first scan all declared fields
+        Field[] fields = target.getDeclaredFields();
+
+        for (Field field : fields)
+        {
+            if (EntityManager.class.equals(field.getType()))
+            {
+                // also check if this is an injected EM
+                if (field.getAnnotation(Inject.class) != null)
+                {
+                    boolean qualifierFound = false;
+                    Class<? extends Annotation> qualifier = getFirstQualifierAnnotation(field.getAnnotations());
+                    if (qualifier != null)
+                    {
+                        emQualifiers.add(qualifier);
+                        qualifierFound = true;
+                    }
+
+                    if (!qualifierFound)
+                    {
+                        // according to the CDI injection rules @Default is assumed
+                        emQualifiers.add(Default.class);
+                    }
+                }
+            }
+        }
+
+        // finally recurse into the superclasses
+        Class superClass = target.getSuperclass();
+        if (!Object.class.equals(superClass))
+        {
+            collectEntityManagerQualifiersOnClass(emQualifiers, superClass);
+        }
+    }
+
+    /**
+     * Extract the first CDI-Qualifier Annotation from the given annotations array
+     */
+    private Class<? extends Annotation> getFirstQualifierAnnotation(Annotation[] annotations)
+    {
+        for (Annotation ann : annotations)
+        {
+            if (beanManager.isQualifier(ann.annotationType()))
+            {
+                return ann.annotationType();
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * @return the &#064;Transactional annotation from either the method or class
+     *         or <code>null</code> if none present.
+     */
+    protected Transactional extractTransactionalAnnotation(InvocationContext context)
+    {
+        // try to detect the interceptor on the method
+        Transactional transactionalAnnotation = extractTransactionalAnnotation(context.getMethod().getAnnotations());
+
+        if (transactionalAnnotation == null)
+        {
+            // and if not found search on the class
+            transactionalAnnotation = extractTransactionalAnnotation(context.getTarget().getClass().getAnnotations());
+        }
+        return transactionalAnnotation;
+    }
+
+    /**
+     * @return a &#064;Transactional annotation extracted from the list of given annotations
+     *         or <code>null</code> if none present.
+     */
+    private Transactional extractTransactionalAnnotation(Annotation[] annotations)
+    {
+        for (Annotation annotation : annotations)
+        {
+            if (Transactional.class.equals(annotation.annotationType()))
+            {
+                return (Transactional) annotation;
+            }
+            if (beanManager.isStereotype(annotation.annotationType()))
+            {
+                Transactional transactionalAnnotation =
+                        extractTransactionalAnnotation(annotation.annotationType().getAnnotations());
+                if (transactionalAnnotation != null)
+                {
+                    return transactionalAnnotation;
+                }
+            }
+        }
+
+        return null;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/94327565/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/TransactionBeanStorageCleanupTestEvent.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/TransactionBeanStorageCleanupTestEvent.java b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/TransactionBeanStorageCleanupTestEvent.java
deleted file mode 100644
index 4a50658..0000000
--- a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/TransactionBeanStorageCleanupTestEvent.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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;
-
-public class TransactionBeanStorageCleanupTestEvent
-{
-}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/94327565/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/TransactionMetaDataEntry.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/TransactionMetaDataEntry.java b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/TransactionMetaDataEntry.java
deleted file mode 100644
index 997f4bc..0000000
--- a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/TransactionMetaDataEntry.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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 javax.persistence.EntityManager;
-
-class TransactionMetaDataEntry
-{
-    private final String id;
-    private EntityManager entityManager;
-
-    private int methodCallDepth = 0;
-
-    private int startLevel = -1;
-
-    TransactionMetaDataEntry(String id, EntityManager entityManager)
-    {
-        this.id = id;
-        this.entityManager = entityManager;
-    }
-
-    String getId()
-    {
-        return id;
-    }
-
-    void enterNewMethodLevel()
-    {
-        this.methodCallDepth++;
-    }
-
-    void leave()
-    {
-        this.methodCallDepth--;
-    }
-
-    int getMethodCallDepth()
-    {
-        return methodCallDepth;
-    }
-
-    EntityManager getEntityManager()
-    {
-        return entityManager;
-    }
-
-    int getStartLevel()
-    {
-        return startLevel;
-    }
-
-    @Deprecated
-    void markLevel()
-    {
-        this.startLevel = this.methodCallDepth;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/94327565/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/TransactionalInterceptor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/TransactionalInterceptor.java b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/TransactionalInterceptor.java
index 8d57694..a7eec08 100644
--- a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/TransactionalInterceptor.java
+++ b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/TransactionalInterceptor.java
@@ -29,6 +29,9 @@ import java.io.Serializable;
 
 /**
  * Interceptor for wrapping transactional database requests.
+ * This interceptor itself doesn't contain any functionality.
+ * Instead the 'real' work is done inside a pluggable
+ * {@link PersistenceStrategy}.
  */
 @Interceptor
 @Transactional

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/94327565/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/TransactionalInterceptorStrategy.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/TransactionalInterceptorStrategy.java b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/TransactionalInterceptorStrategy.java
index 5d8022d..1d07120 100644
--- a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/TransactionalInterceptorStrategy.java
+++ b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/TransactionalInterceptorStrategy.java
@@ -18,18 +18,13 @@
  */
 package org.apache.deltaspike.jpa.impl.transaction;
 
-import org.apache.deltaspike.core.api.projectstage.TestStage;
-import org.apache.deltaspike.core.util.ProjectStageProducer;
+
+import org.apache.deltaspike.core.api.literal.AnyLiteral;
 import org.apache.deltaspike.jpa.api.Transactional;
-import org.apache.deltaspike.jpa.impl.EntityManagerRef;
-import org.apache.deltaspike.jpa.impl.PersistenceHelper;
 import org.apache.deltaspike.jpa.impl.transaction.context.TransactionBeanStorage;
 import org.apache.deltaspike.jpa.spi.PersistenceStrategy;
-
-import javax.annotation.PostConstruct;
 import javax.enterprise.context.Dependent;
-import javax.enterprise.inject.Any;
-import javax.enterprise.inject.Default;
+import javax.enterprise.inject.spi.Bean;
 import javax.enterprise.inject.spi.BeanManager;
 import javax.inject.Inject;
 import javax.interceptor.InvocationContext;
@@ -37,130 +32,129 @@ import javax.persistence.EntityManager;
 import javax.persistence.EntityTransaction;
 import java.lang.annotation.Annotation;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * <p>Default implementation of our pluggable PersistenceStrategy.
+ * <p>Default implementation of our plugable PersistenceStrategy.
  * It supports nested Transactions with the MANDATORY behaviour.</p>
- * <p/>
+ *
  * <p>The outermost &#064;Transactional interceptor for the given
  * {@link javax.inject.Qualifier} will open an {@link javax.persistence.EntityTransaction}
  * and the outermost &#064;Transactional interceptor for <b>all</b>
  * EntityManagers will flush and subsequently close all open transactions.</p>
- * <p/>
+ *
  * <p>If an Exception occurs in flushing the EntityManagers or any other Exception
  * gets thrown inside the intercepted method chain and <i>not</i> gets catched
  * until the outermost &#064;Transactional interceptor gets reached, then all
  * open transactions will get rollbacked.</p>
- * <p/>
+ *
  * <p>If you like to implement your own PersistenceStrategy, then use the
  * standard CDI &#064;Alternative mechanism.</p>
  */
 @Dependent
 public class TransactionalInterceptorStrategy implements PersistenceStrategy
 {
-    private static final long serialVersionUID = 2433371956913151976L;
+    private static final long serialVersionUID = -1432802805095533499L;
 
     private static final Logger LOGGER = Logger.getLogger(TransactionalInterceptorStrategy.class.getName());
 
-    /**
-     * key=qualifier name, value= reference counter
-     */
-    private static transient ThreadLocal<InternalTransactionContext> transactionContext =
-            new ThreadLocal<InternalTransactionContext>();
-
     @Inject
     private BeanManager beanManager;
 
-    private boolean isTestProjectStage;
+    @Inject
+    private TransactionBeanStorage transactionBeanStorage;
+
+    @Inject
+    private PersistenceStrategyHelper persistenceHelper;
 
-    @PostConstruct
-    protected void init()
-    {
-        this.isTestProjectStage = TestStage.class.isAssignableFrom(
-            ProjectStageProducer.getInstance().getProjectStage().getClass());
-    }
 
     public Object execute(InvocationContext invocationContext) throws Exception
     {
-        Transactional transactionalAnnotation = extractTransactionalAnnotation(invocationContext);
+        Transactional transactionalAnnotation = persistenceHelper.extractTransactionalAnnotation(invocationContext);
 
-        //TODO add support for entity managers injected as argument/s
+        // all the configured qualifier keys
+        Set<Class<? extends Annotation>> emQualifiers = persistenceHelper.resolveEntityManagerQualifiers(
+                    transactionalAnnotation, invocationContext.getTarget().getClass());
 
-        InternalTransactionContext currentTransactionContext =
-                getOrCreateTransactionContext(transactionalAnnotation, invocationContext.getTarget());
+        List<EntityManager> ems = new ArrayList<EntityManager>();
 
-        List<String> transactionKeys = getTransactionKeys(currentTransactionContext);
+        boolean isOutermostInterceptor = transactionBeanStorage.isEmpty();
 
-        if (TransactionBeanStorage.getStorage() == null)
+        if (isOutermostInterceptor)
         {
-            TransactionBeanStorage.activateNewStorage();
+            // a new Context needs to get started
+            transactionBeanStorage.startTransactionScope();
         }
 
-        for (String transactionKey : transactionKeys)
-        {
-            TransactionBeanStorage.getStorage().startTransactionScope(transactionKey);
-        }
+        // the 'layer' of the transactional invocation, aka the refCounter
+        int transactionLayer = transactionBeanStorage.incrementRefCounter();
 
-        List<String> previousTransactionKeys = null;
 
-        if (transactionKeys != null && !transactionKeys.isEmpty())
+        for (Class<? extends Annotation> emQualifier : emQualifiers)
         {
-            TransactionBeanStorage.getStorage().activateTransactionScope(transactionKeys);
+            EntityManager entityManager = resolveEntityManagerForQualifier(emQualifier);
+
+            transactionBeanStorage.storeUsedEntityManager(emQualifier, entityManager);
+
+            ems.add(entityManager);
         }
 
-        beginOrJoinTransactionsAndEnter(currentTransactionContext);
 
-        // used to store any exception we get from the services
         Exception firstException = null;
 
         try
         {
+            for (EntityManager entityManager : ems)
+            {
+                EntityTransaction transaction = entityManager.getTransaction();
+
+                if (!transaction.isActive())
+                {
+                    transaction.begin();
+                }
+            }
+
             return invocationContext.proceed();
         }
         catch (Exception e)
         {
             firstException = e;
 
-            leave(currentTransactionContext);
             // we only cleanup and rollback all open transactions in the outermost interceptor!
             // this way, we allow inner functions to catch and handle exceptions properly.
-            if (isOutermostInterceptor(currentTransactionContext))
+            if (isOutermostInterceptor)
             {
-                for (TransactionMetaDataEntry transactionMetaDataEntry :
-                        currentTransactionContext.getTransactionMetaDataEntries())
+                HashMap<Class, EntityManager> emsEntries = transactionBeanStorage.getUsedEntityManagers();
+                for (Map.Entry<Class, EntityManager> emsEntry: emsEntries.entrySet())
                 {
-                    try
+                    EntityManager em = emsEntry.getValue();
+                    EntityTransaction transaction = em.getTransaction();
+                    if (transaction != null && transaction.isActive())
                     {
-                        EntityTransaction transaction = transactionMetaDataEntry.getEntityManager().getTransaction();
-
-                        if (transaction != null && transaction.isActive())
+                        try
                         {
-                            try
-                            {
-                                transaction.rollback();
-                            }
-                            catch (Exception eRollback)
+                            transaction.rollback();
+                        }
+                        catch (Exception eRollback)
+                        {
+                            if (LOGGER.isLoggable(Level.SEVERE))
                             {
-                                if (LOGGER.isLoggable(Level.SEVERE))
-                                {
-                                    LOGGER.log(Level.SEVERE,
-                                            "Got additional Exception while subsequently " +
-                                                    "rolling back other SQL transactions", eRollback);
-                                }
+                                LOGGER.log(Level.SEVERE,
+                                        "Got additional Exception while subsequently " +
+                                                "rolling back other SQL transactions", eRollback);
                             }
                         }
                     }
-                    catch (IllegalStateException e2)
-                    {
-                        //just happens if the setup is wrong -> we can't do a proper cleanup
-                        //but we have to continue to cleanup the scope
-                    }
                 }
 
-                cleanupTransactionBeanStorage();
+                // drop all EntityManagers from the ThreadLocal
+                transactionBeanStorage.cleanUsedEntityManagers();
             }
 
             // give any extensions a chance to supply a better error message
@@ -168,6 +162,7 @@ public class TransactionalInterceptorStrategy implements PersistenceStrategy
 
             // rethrow the exception
             throw e;
+
         }
         finally
         {
@@ -175,32 +170,28 @@ public class TransactionalInterceptorStrategy implements PersistenceStrategy
             // in this case, we rollback all later transactions too.
             boolean commitFailed = false;
 
-            // only commit all transactions if we didn't rollback them already
-            if (firstException == null)
+            // commit all open transactions in the outermost interceptor!
+            // this is a 'JTA for poor men' only, and will not guaranty
+            // commit stability over various databases!
+            if (isOutermostInterceptor)
             {
-                leave(currentTransactionContext);
 
-                // commit all open transactions in the outermost interceptor!
-                // this is a 'JTA for poor men' only, and will not guaranty
-                // commit stability over various databases!
-                if (isOutermostInterceptor(currentTransactionContext))
+                // only commit all transactions if we didn't rollback
+                // them already
+                if (firstException == null)
                 {
-                    EntityTransaction transaction;
-                    EntityManager entityManager;
+                    HashMap<Class, EntityManager> emsEntries = transactionBeanStorage.getUsedEntityManagers();
                     // but first try to flush all the transactions and write the updates to the database
-                    for (TransactionMetaDataEntry transactionMetaDataEntry :
-                            currentTransactionContext.getTransactionMetaDataEntries())
+                    for (EntityManager em: emsEntries.values())
                     {
-                        entityManager = transactionMetaDataEntry.getEntityManager();
-                        transaction = entityManager.getTransaction();
-
+                        EntityTransaction transaction = em.getTransaction();
                         if (transaction != null && transaction.isActive())
                         {
                             try
                             {
                                 if (!commitFailed)
                                 {
-                                    entityManager.flush();
+                                    em.flush();
                                 }
                             }
                             catch (Exception e)
@@ -213,19 +204,16 @@ public class TransactionalInterceptorStrategy implements PersistenceStrategy
                     }
 
                     // and now either commit or rollback all transactions
-                    for (TransactionMetaDataEntry transactionMetaDataEntry :
-                            currentTransactionContext.getTransactionMetaDataEntries())
+                    for (EntityManager em : emsEntries.values())
                     {
-                        entityManager = transactionMetaDataEntry.getEntityManager();
-                        transaction = entityManager.getTransaction();
-
+                        EntityTransaction transaction = em.getTransaction();
                         if (transaction != null && transaction.isActive())
                         {
                             try
                             {
                                 if (!commitFailed)
                                 {
-                                    transaction.commit(); //shouldn't fail since the transaction was flushed already
+                                    transaction.commit();
                                 }
                                 else
                                 {
@@ -239,20 +227,14 @@ public class TransactionalInterceptorStrategy implements PersistenceStrategy
                             }
                         }
                     }
-                    cleanupTransactionBeanStorage();
-                }
-                else
-                {
-                    // we are NOT the outermost TransactionInterceptor
-                    // so we have to re-activate the previous transaction
-                    if (previousTransactionKeys != null && !previousTransactionKeys.isEmpty())
-                    {
-                        TransactionBeanStorage.getStorage().activateTransactionScope(previousTransactionKeys);
-                    }
+
+                    // and now we close the open transaction scope
+                    transactionBeanStorage.endTransactionScope();
                 }
+
             }
 
-            cleanup(currentTransactionContext);
+            transactionBeanStorage.decrementRefCounter();
 
             if (commitFailed)
             {
@@ -262,202 +244,54 @@ public class TransactionalInterceptorStrategy implements PersistenceStrategy
         }
     }
 
-    private void cleanupTransactionBeanStorage()
-    {
-        // and now we close all open transaction-scopes and reset the storage
-        TransactionBeanStorage.getStorage().endAllTransactionScopes();
-        TransactionBeanStorage.resetStorage();
-    }
-
-    private List<String> getTransactionKeys(InternalTransactionContext currentTransactionContext)
-    {
-        List<String> transactionKeys = new ArrayList<String>();
-
-        for (TransactionMetaDataEntry transactionMetaDataEntry :
-                currentTransactionContext.getTransactionMetaDataEntries())
-        {
-            if (transactionMetaDataEntry.getMethodCallDepth() == 0)
-            {
-                transactionKeys.add(transactionMetaDataEntry.getId());
-            }
-        }
 
-        return transactionKeys;
-    }
-
-    private void removeTransactionContext()
+    private EntityManager resolveEntityManagerForQualifier(Class<? extends Annotation> emQualifier)
     {
-        if (this.isTestProjectStage)
-        {
-            this.beanManager.fireEvent(new PersistenceStrategyCleanupTestEvent());
-        }
+        Bean<EntityManager> entityManagerBean = resolveEntityManagerBean(emQualifier);
 
-        transactionContext.set(null);
-        transactionContext.remove();
-    }
-
-    private void startTransactionStorage(String transactionKey)
-    {
-        if (TransactionBeanStorage.getStorage() == null)
+        if (entityManagerBean == null)
         {
-            TransactionBeanStorage.activateNewStorage();
+            return null;
         }
 
-        TransactionBeanStorage.getStorage().startTransactionScope(transactionKey);
-    }
-
-    private void beginOrJoinTransactionsAndEnter(InternalTransactionContext transactionContext)
-    {
-        for (TransactionMetaDataEntry transactionMetaDataEntry : transactionContext.getTransactionMetaDataEntries())
-        {
-            if (transactionMetaDataEntry.getMethodCallDepth() == 0)
-            {
-                startTransactionStorage(transactionMetaDataEntry.getId());
-
-                beginTransaction(transactionMetaDataEntry);
-            }
-            transactionMetaDataEntry.enterNewMethodLevel();
-        }
-    }
-
-    private void beginTransaction(TransactionMetaDataEntry transactionMetaDataEntry)
-    {
-        EntityManager entityManager = transactionMetaDataEntry.getEntityManager();
-
-        EntityTransaction transaction = entityManager.getTransaction();
-
-        if (!transaction.isActive())
-        {
-            transaction.begin();
-            transactionMetaDataEntry.markLevel();
-        }
+        return (EntityManager) beanManager.getReference(entityManagerBean, EntityManager.class,
+                beanManager.createCreationalContext(entityManagerBean));
     }
 
     /**
      * This method might get overridden in subclasses to supply better error messages.
      * This is useful if e.g. a JPA provider only provides a stubborn Exception for
      * their ConstraintValidationExceptions.
+     * @param e
+     * @return the wrapped or unwrapped Exception
      */
     protected Exception prepareException(Exception e)
     {
         return e;
     }
 
-    protected Transactional extractTransactionalAnnotation(InvocationContext context)
-    {
-        Transactional transactionalAnnotation = context.getMethod().getAnnotation(Transactional.class);
-
-        if (transactionalAnnotation == null)
-        {
-            transactionalAnnotation = context.getTarget().getClass().getAnnotation(Transactional.class);
-        }
-
-        //check class stereotypes
-        if (transactionalAnnotation == null)
-        {
-            for (Annotation annotation : context.getTarget().getClass().getAnnotations())
-            {
-                if (this.beanManager.isQualifier(annotation.annotationType()))
-                {
-                    for (Annotation metaAnnotation : annotation.annotationType().getAnnotations())
-                    {
-                        if (Transactional.class.isAssignableFrom(metaAnnotation.annotationType()))
-                        {
-                            return (Transactional) metaAnnotation;
-                        }
-                    }
-                }
-            }
-        }
 
-        return transactionalAnnotation;
-    }
 
-    private InternalTransactionContext getOrCreateTransactionContext(Transactional transactionalAnnotation,
-                                                                     Object target)
+    protected Bean<EntityManager> resolveEntityManagerBean(Class<? extends Annotation> qualifierClass)
     {
-        InternalTransactionContext currentTransactionContext = transactionContext.get();
-
-        if (currentTransactionContext == null)
+        Set<Bean<?>> entityManagerBeans = beanManager.getBeans(EntityManager.class, new AnyLiteral());
+        if (entityManagerBeans == null)
         {
-            currentTransactionContext = new InternalTransactionContext(beanManager);
-            transactionContext.set(currentTransactionContext);
+            entityManagerBeans = new HashSet<Bean<?>>();
         }
 
-        if (transactionalAnnotation == null)
-        {
-            //TODO check if we still need it
-            currentTransactionContext.addTransactionMetaDataEntry(Default.class);
-        }
-        else if (!Any.class.isAssignableFrom(transactionalAnnotation.qualifier()[0]))
+        for (Bean<?> currentEntityManagerBean : entityManagerBeans)
         {
-            for (Class<? extends Annotation> qualifier : transactionalAnnotation.qualifier())
-            {
-                currentTransactionContext.addTransactionMetaDataEntry(qualifier);
-            }
-        }
-        else
-        {
-            findAndAddInjectedEntityManagers(target, currentTransactionContext);
-        }
-
-        return currentTransactionContext;
-    }
-
-    private void findAndAddInjectedEntityManagers(Object target, InternalTransactionContext currentTransactionContext)
-    {
-        List<EntityManagerRef> entityManagerRefList = PersistenceHelper.tryToFindEntityManagerReference(target);
-
-        if (entityManagerRefList == null)
-        {
-            return;
-        }
-
-        for (EntityManagerRef entityManagerRef : entityManagerRefList)
-        {
-            currentTransactionContext.addTransactionMetaDataEntry(
-                    entityManagerRef.getKey(), entityManagerRef.getEntityManager(target));
-        }
-    }
+            Set<Annotation> foundQualifierAnnotations = currentEntityManagerBean.getQualifiers();
 
-    private void leave(InternalTransactionContext currentTransactionContext)
-    {
-        for (TransactionMetaDataEntry transactionMetaDataEntry :
-                currentTransactionContext.getTransactionMetaDataEntries())
-        {
-            transactionMetaDataEntry.leave();
-        }
-    }
-
-    private boolean isOutermostInterceptor(InternalTransactionContext currentTransactionContext)
-    {
-        for (TransactionMetaDataEntry transactionMetaDataEntry :
-                currentTransactionContext.getTransactionMetaDataEntries())
-        {
-            //can be < 0 if a 2nd entity-manager is used for a nested call which
-            //should be committed/rolled back before the outermost method returns
-            if (transactionMetaDataEntry.getMethodCallDepth() > 0)
+            for (Annotation currentQualifierAnnotation : foundQualifierAnnotations)
             {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    private void cleanup(InternalTransactionContext currentTransactionContext)
-    {
-        for (TransactionMetaDataEntry transactionMetaDataEntry :
-                currentTransactionContext.getTransactionMetaDataEntries())
-        {
-            //can be < 0 if a 2nd entity-manager is used for a nested call which
-            //should be committed/rolled back before the outermost method returns
-            if (transactionMetaDataEntry.getMethodCallDepth() > 0)
-            {
-                return;
+                if (currentQualifierAnnotation.annotationType().equals(qualifierClass))
+                {
+                    return (Bean<EntityManager>) currentEntityManagerBean;
+                }
             }
         }
-
-        removeTransactionContext();
+        return null;
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/94327565/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/context/TransactionBeanEntry.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/context/TransactionBeanEntry.java b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/context/TransactionBeanEntry.java
index 5b13a9c..c96b1c2 100644
--- a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/context/TransactionBeanEntry.java
+++ b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/context/TransactionBeanEntry.java
@@ -20,10 +20,6 @@ package org.apache.deltaspike.jpa.impl.transaction.context;
 
 import javax.enterprise.context.spi.Contextual;
 import javax.enterprise.context.spi.CreationalContext;
-import javax.enterprise.inject.spi.Bean;
-import java.lang.annotation.Annotation;
-import java.util.Collections;
-import java.util.Set;
 
 /**
  * Holds the information we need store to manage
@@ -57,13 +53,4 @@ public class TransactionBeanEntry<T>
     {
         return creationalContext;
     }
-
-    public Set<Annotation> getQualifiers()
-    {
-        if (bean instanceof Bean)
-        {
-            return ((Bean<?>) bean).getQualifiers();
-        }
-        return Collections.emptySet();
-    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/94327565/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/context/TransactionBeanStorage.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/context/TransactionBeanStorage.java b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/context/TransactionBeanStorage.java
index a06cac9..f6a6b49 100644
--- a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/context/TransactionBeanStorage.java
+++ b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/context/TransactionBeanStorage.java
@@ -18,229 +18,200 @@
  */
 package org.apache.deltaspike.jpa.impl.transaction.context;
 
-import org.apache.deltaspike.core.api.projectstage.TestStage;
-import org.apache.deltaspike.core.api.provider.BeanManagerProvider;
-import org.apache.deltaspike.core.util.ProjectStageProducer;
-import org.apache.deltaspike.jpa.impl.transaction.TransactionBeanStorageCleanupTestEvent;
-
+import javax.annotation.PreDestroy;
+import javax.enterprise.context.RequestScoped;
 import javax.enterprise.context.spi.Contextual;
-import javax.enterprise.inject.Typed;
-import java.util.ArrayList;
-import java.util.Collections;
+import javax.persistence.EntityManager;
+import java.lang.annotation.Annotation;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
+import java.util.Stack;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * <p>This bean stores information about
+ * <p>This class stores information about
  * &#064;{@link org.apache.deltaspike.jpa.api.TransactionScoped}
  * contextual instances, their {@link javax.enterprise.context.spi.CreationalContext} etc.</p>
- * <p/>
+ *
  * <p>We use a RequestScoped bean because this way we don't need to take
  * care about cleaning up any ThreadLocals ourselves. This also makes sure that
  * we subsequently destroy any left over TransactionScoped beans (which should not happen,
  * but who knows). We also don't need to do any fancy synchronization stuff since
  * we are sure that we are always in the same Thread.</p>
  */
-@Typed()
+@RequestScoped
 public class TransactionBeanStorage
 {
     private static final Logger LOGGER = Logger.getLogger(TransactionBeanStorage.class.getName());
 
-    private static ThreadLocal<TransactionBeanStorage> currentStorage = new ThreadLocal<TransactionBeanStorage>();
+    private static class TransactionContextInfo
+    {
+        /**
+         * This is the actual bean storage.
+         * The structure is:
+         * <ol>
+         *     <li>transactioKey identifies the 'database qualifier'</li>
+         *     <li>transactionKey -> Stack: we need the Stack because of REQUIRES_NEW, etc</li>
+         *     <li>top Element in the Stack -> Context beans for the transactionKey</li>
+         * </ol>
+         *
+         */
+        private Map<Contextual, TransactionBeanEntry> contextualInstances =
+                new HashMap<Contextual, TransactionBeanEntry>();
+
+        /** key=qualifier name, value= EntityManager */
+        private HashMap<Class, EntityManager> ems = new HashMap<Class, EntityManager>();
+
+        /**
+         * counts the 'depth' of the interceptor invocation.
+         */
+        private AtomicInteger refCounter = new AtomicInteger(0);
+    }
 
     /**
-     * This is the actual bean storage.
-     * The structure is:
-     * <ol>
-     * <li>transactioKey identifies the 'database qualifier'</li>
-     * <li>transactionKey -> Stack: we need the Stack because of REQUIRES_NEW, etc</li>
-     * <li>top Element in the Stack -> Context beans for the transactionKey</li>
-     * </ol>
+     * If we hit a layer with REQUIRES_NEW, then create a new TransactionContextInfo
+     * and push the old one on top of this stack.
      */
-    private Map<String, Map<Contextual, TransactionBeanEntry>> storedTransactionContexts =
-            new HashMap<String, Map<Contextual, TransactionBeanEntry>>();
-
-    private List<Map<Contextual, TransactionBeanEntry>> activeTransactionContextList;
-
-    private List<String> activeTransactionKeyList = new ArrayList<String>();
-
-    private boolean isTestProjectStage;
-
-    private TransactionBeanStorage()
-    {
-        this.isTestProjectStage = TestStage.class.isAssignableFrom(
-            ProjectStageProducer.getInstance().getProjectStage().getClass());
-    }
+    private Stack<TransactionContextInfo> oldTci = new Stack<TransactionContextInfo>();
 
     /**
-     * @return the storage for the current thread if there is one - null otherwise
+     * The TransactionContextInfo which is on top of the stack.
      */
-    public static TransactionBeanStorage getStorage()
-    {
-        return currentStorage.get();
-    }
+    private TransactionContextInfo currentTci = null;
 
     /**
-     * Creates a new storage for the current thread
+     * Increment the ref counter and return the old value.
+     * Must only be called if the bean storage is not {@link #isEmpty()}.
      *
-     * @return the storage which was associated with the thread before - null if there was no storage
+     * @return the the previous values of the refCounters. If 0 then we are 'outermost'
      */
-    public static TransactionBeanStorage activateNewStorage()
+    public int incrementRefCounter()
     {
-        TransactionBeanStorage previousStorage = currentStorage.get();
-        currentStorage.set(new TransactionBeanStorage());
-        return previousStorage;
+        return currentTci.refCounter.incrementAndGet() - 1;
     }
 
     /**
-     * Removes the current storage
+     * Decrement the reference counter and return the layer.
+     *
+     * @return the layer number. 0 represents the outermost interceptor for the qualifier
      */
-    public static void resetStorage()
+    public int decrementRefCounter()
     {
-        TransactionBeanStorage currentBeanStorage = currentStorage.get();
-
-        if (currentBeanStorage != null)
+        if (currentTci == null)
         {
-            currentBeanStorage.close();
-
-            currentStorage.set(null);
-            currentStorage.remove();
+            return 0;
         }
+
+        return currentTci.refCounter.decrementAndGet();
     }
 
-    private void close()
+
+    /**
+     * @return <code>true</code> if we are the outermost interceptor over all qualifiers
+     *         and the TransactionBeanStorage is yet empty.
+     */
+    public boolean isEmpty()
     {
-        if (this.isTestProjectStage)
-        {
-            BeanManagerProvider.getInstance().getBeanManager().fireEvent(new TransactionBeanStorageCleanupTestEvent());
-        }
+        return currentTci == null;
     }
 
     /**
-     * Start the TransactionScope with the given qualifier
-     *
-     * @param transactionKey
+     * Start a new TransactionScope
+     * @return the
      */
-    public void startTransactionScope(String transactionKey)
+    public void startTransactionScope()
     {
-        if (LOGGER.isLoggable(Level.FINER))
+        // first store away any previous TransactionContextInfo
+        if (currentTci != null)
         {
-            LOGGER.finer("starting TransactionScope " + transactionKey);
+            oldTci.push(currentTci);
         }
+        currentTci = new TransactionContextInfo();
 
-        Map<Contextual, TransactionBeanEntry> transactionBeanEntryMap = storedTransactionContexts.get(transactionKey);
-
-        if (transactionBeanEntryMap == null)
+        if (LOGGER.isLoggable(Level.FINER))
         {
-            transactionBeanEntryMap = new HashMap<Contextual, TransactionBeanEntry>();
-            storedTransactionContexts.put(transactionKey, transactionBeanEntryMap);
+            LOGGER.finer( "starting TransactionScope");
         }
     }
 
     /**
-     * Activate the TransactionScope with the given qualifier.
-     * This is needed if a subsequently invoked &#064;Transactional
-     * method will switch to another persistence unit.
-     * This method must also be invoked when the transaction just got started
-     * with {@link #startTransactionScope(String)}.
+     * End the TransactionScope with the given qualifier.
+     * This will subsequently destroy all beans which are stored
+     * in the context.
+     *
+     * This method only gets used if we leave a transaction with REQUIRES_NEW.
+     * In all other cases we use {@link #endAllTransactionScopes()}.
      */
-    public void activateTransactionScope(List<String> transactionKeyList)
+    public void endTransactionScope()
     {
-        //TODO remove it after a review
-        /*
-        if (transactionKeyList != null && transactionKeyList.isEmpty())
-        {
-            transactionKeyList.add(Default.class.getName()); //needed for the transaction test helper
-        }
-        */
-
         if (LOGGER.isLoggable(Level.FINER))
         {
-            if (transactionKeyList != null && LOGGER.isLoggable(Level.FINER))
-            {
-                for (String transactionKey : transactionKeyList)
-                {
-                    LOGGER.finer("activating TransactionScope " + transactionKey);
-                }
-            }
+            LOGGER.finer("ending TransactionScope");
         }
 
-        //can be null on the topmost stack-layer
-        if (transactionKeyList == null && this.activeTransactionKeyList == null)
-        {
-            return;
-        }
+        destroyBeans(currentTci.contextualInstances);
 
-        if (transactionKeyList == null)
+        if (oldTci.size() > 0)
         {
-            transactionKeyList = this.activeTransactionKeyList;
+            currentTci = oldTci.pop();
         }
-
-        if (activeTransactionContextList == null)
+        else
         {
-            activeTransactionContextList = new ArrayList<Map<Contextual, TransactionBeanEntry>>();
+            currentTci = null;
         }
+    }
 
-        for (String transactionKey : transactionKeyList)
-        {
-            Map<Contextual, TransactionBeanEntry> transactionBeanEntryMap =
-                    this.storedTransactionContexts.get(transactionKey);
-
-            if (transactionBeanEntryMap == null)
-            {
-                throw new IllegalStateException("Cannot activate TransactionScope with key " + transactionKey);
-            }
 
-            if (!this.activeTransactionContextList.contains(transactionBeanEntryMap))
-            {
-                this.activeTransactionContextList.add(transactionBeanEntryMap);
-            }
-        }
+    public EntityManager storeUsedEntityManager(Class<? extends Annotation> emQualifier, EntityManager entityManager)
+    {
+        return currentTci.ems.put(emQualifier, entityManager);
+    }
 
-        this.activeTransactionKeyList.addAll(transactionKeyList);
+    public HashMap<Class,EntityManager> getUsedEntityManagers()
+    {
+        return currentTci.ems;
     }
 
-    public List<String> getActiveTransactionKeyList()
+    public void cleanUsedEntityManagers()
     {
-        return Collections.unmodifiableList(this.activeTransactionKeyList);
+        currentTci.ems.clear();
     }
 
     /**
-     * This will destroy all stored transaction contexts.
+     * @return the Map which represents the currently active Context content.
      */
-    public void endAllTransactionScopes()
+    public Map<Contextual, TransactionBeanEntry> getActiveTransactionContext()
     {
-        if (LOGGER.isLoggable(Level.FINER))
-        {
-            LOGGER.finer("destroying all TransactionScopes");
-        }
-
-        for (Map<Contextual, TransactionBeanEntry> beans : this.storedTransactionContexts.values())
+        if (currentTci == null)
         {
-            destroyBeans(beans);
+            return null;
         }
 
-        // we also need to clean our active context info
-        storedTransactionContexts.clear();
-        activeTransactionContextList.clear();
-        activeTransactionKeyList.clear();
+        return currentTci.contextualInstances;
     }
 
-
     /**
-     * @return the Map which represents the currently active Context content.
+     * At the end of the request we will destroy all beans still
+     * stored in the context.
      */
-    public List<Map<Contextual, TransactionBeanEntry>> getActiveTransactionContextList()
+    @PreDestroy
+    public void requestEnded()
     {
-        return Collections.unmodifiableList(this.activeTransactionContextList);
+        endAllTransactionScopes();
+    }
+
+    private void endAllTransactionScopes()
+    {
+        while (!isEmpty())
+        {
+            endTransactionScope();
+        }
     }
 
     /**
      * Properly destroy all the given beans.
-     *
      * @param activeBeans
      */
     private void destroyBeans(Map<Contextual, TransactionBeanEntry> activeBeans)
@@ -250,24 +221,5 @@ public class TransactionBeanStorage
             beanBag.getBean().destroy(beanBag.getContextualInstance(), beanBag.getCreationalContext());
         }
     }
-
-    public void storeTransactionBeanEntry(String transactionKey, TransactionBeanEntry transactionBeanEntry)
-    {
-        if (!this.activeTransactionKeyList.contains(transactionKey))
-        {
-            throw new IllegalStateException("Transaction for " + transactionKey + " is not active.");
-        }
-
-        Map<Contextual, TransactionBeanEntry> storedTransactionContext =
-            this.storedTransactionContexts.get(transactionKey);
-
-        if (storedTransactionContext == null)
-        {
-            storedTransactionContext = new HashMap<Contextual, TransactionBeanEntry>();
-            this.storedTransactionContexts.put(transactionKey, storedTransactionContext);
-        }
-
-        storedTransactionContext.put(transactionBeanEntry.getBean(), transactionBeanEntry);
-    }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/94327565/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/context/TransactionContext.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/context/TransactionContext.java b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/context/TransactionContext.java
index f3f9115..f75e4fe 100644
--- a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/context/TransactionContext.java
+++ b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/context/TransactionContext.java
@@ -19,6 +19,8 @@
 package org.apache.deltaspike.jpa.impl.transaction.context;
 
 
+
+import org.apache.deltaspike.core.api.provider.BeanProvider;
 import org.apache.deltaspike.jpa.api.TransactionScoped;
 import org.apache.deltaspike.jpa.api.Transactional;
 
@@ -26,46 +28,34 @@ import javax.enterprise.context.ContextNotActiveException;
 import javax.enterprise.context.spi.Context;
 import javax.enterprise.context.spi.Contextual;
 import javax.enterprise.context.spi.CreationalContext;
-import javax.enterprise.inject.Any;
-import javax.enterprise.inject.Typed;
-import javax.enterprise.inject.spi.Bean;
-import javax.inject.Named;
 import java.lang.annotation.Annotation;
-import java.util.HashSet;
-import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 /**
- * CDI Context for managing &#064;{@link TransactionScoped} contextual instances.
+ * CDI Context for managing &#064;{@link org.apache.deltaspike.jpa.api.TransactionScoped} contextual instances.
  */
-@Typed()
 public class TransactionContext implements Context
 {
-    public <T> T get(Contextual<T> component)
-    {
-        List<Map<Contextual, TransactionBeanEntry>> transactionBeanEntryMaps = getTransactionBeanEntryMaps();
+    // Attention! this is not a normal instance but a PROXY
+    // thus it resolves the correct contextual instance every time
+    // it will lazily initialized at runtime after the container
+    // got started.
+    private TransactionBeanStorage beanStorage;
 
-        if (transactionBeanEntryMaps == null)
-        {
-            return null;
-        }
 
-        TransactionBeanEntry transactionBeanEntry = null;
+    public <T> T get(Contextual<T> component)
+    {
+        Map<Contextual, TransactionBeanEntry> transactionBeanEntryMap = getBeanStorage().getActiveTransactionContext();
 
-        for (Map<Contextual, TransactionBeanEntry> transactionBeanEntryMap : transactionBeanEntryMaps)
+        if (transactionBeanEntryMap == null)
         {
-            transactionBeanEntry = transactionBeanEntryMap.get(component);
-
-            if (transactionBeanEntry != null)
-            {
-                break;
-            }
+            throw new ContextNotActiveException("Not accessed within a transactional method - use @" +
+                    Transactional.class.getName());
         }
 
+        TransactionBeanEntry transactionBeanEntry = transactionBeanEntryMap.get(component);
         if (transactionBeanEntry != null)
         {
-            checkTransactionBeanEntry(transactionBeanEntry);
             return (T) transactionBeanEntry.getContextualInstance();
         }
 
@@ -74,130 +64,55 @@ public class TransactionContext implements Context
 
     public <T> T get(Contextual<T> component, CreationalContext<T> creationalContext)
     {
-        if (!(component instanceof Bean))
-        {
-            throw new IllegalStateException(Contextual.class.getName() + " is not of type " + Bean.class.getName());
-        }
+        Map<Contextual, TransactionBeanEntry> transactionBeanEntryMap = getBeanStorage().getActiveTransactionContext();
 
-        Set<Annotation> qualifiers = ((Bean)component).getQualifiers();
-        Set<Annotation> transactionKeys = new HashSet<Annotation>();
-
-        for (Annotation currentQualifier : qualifiers)
-        {
-            if (Any.class.isAssignableFrom(currentQualifier.annotationType()))
-            {
-                continue;
-            }
-            if (Named.class.isAssignableFrom(currentQualifier.annotationType()))
-            {
-                continue;
-            }
-
-            //TODO since we just support a simple qualifier as key, we can exclude all other qualifiers
-
-            transactionKeys.add(currentQualifier);
-        }
-        
-        if (transactionKeys.size() != 1)
-        {
-            throw new IllegalStateException(transactionKeys.size() + " qualifiers found at " + component.toString() +
-                " only one is allowed!");
-        }
-        
-        String transactionKey = transactionKeys.iterator().next().annotationType().getName();
-        
-        if (TransactionBeanStorage.getStorage().getActiveTransactionContextList() == null)
-        {
-            TransactionBeanStorage.activateNewStorage();
-        }
-
-        List<Map<Contextual, TransactionBeanEntry>> activeTransactionBeanEntryMaps = getTransactionBeanEntryMaps();
-
-        if (activeTransactionBeanEntryMaps == null)
+        if (transactionBeanEntryMap == null)
         {
             throw new ContextNotActiveException("Not accessed within a transactional method - use @" +
                     Transactional.class.getName());
         }
 
-        TransactionBeanEntry transactionBeanEntry;
-        if (!activeTransactionBeanEntryMaps.isEmpty())
+        TransactionBeanEntry transactionBeanEntry = transactionBeanEntryMap.get(component);
+        if (transactionBeanEntry != null)
         {
-            for (Map<Contextual, TransactionBeanEntry> currentTransactionBeanEntryMap : activeTransactionBeanEntryMaps)
-            {
-                transactionBeanEntry = currentTransactionBeanEntryMap.get(component);
-
-                if (transactionBeanEntry != null)
-                {
-                    checkTransactionBeanEntry(transactionBeanEntry);
-                    return (T) transactionBeanEntry.getContextualInstance();
-                }
-            }
+            return (T) transactionBeanEntry.getContextualInstance();
         }
 
         // if it doesn't yet exist, we need to create it now!
         T instance = component.create(creationalContext);
         transactionBeanEntry = new TransactionBeanEntry(component, instance, creationalContext);
-
-        checkTransactionBeanEntry(transactionBeanEntry);
-
-        TransactionBeanStorage.getStorage().storeTransactionBeanEntry(transactionKey, transactionBeanEntry);
+        transactionBeanEntryMap.put(component, transactionBeanEntry);
 
         return instance;
     }
 
-    private void checkTransactionBeanEntry(TransactionBeanEntry<?> transactionBeanEntry)
+    public Class<? extends Annotation> getScope()
     {
-        List<String> activeTransactionKeys = TransactionBeanStorage.getStorage().getActiveTransactionKeyList();
-
-        for (Annotation qualifier : transactionBeanEntry.getQualifiers())
-        {
-            if (activeTransactionKeys.contains(qualifier.annotationType().getName()))
-            {
-                return;
-            }
-        }
-
-        throw new IllegalStateException("Transaction qualifier of the intercepted bean or method and " +
-                "the injected entity-manager has to be the same. Active transaction qualifier: " +
-                //TODO
-                activeTransactionKeys + " qualifier/s of the entity-manager: " +
-                extractQualifiers(transactionBeanEntry));
+        return TransactionScoped.class;
     }
 
-    private String extractQualifiers(TransactionBeanEntry<?> transactionBeanEntry)
+    public boolean isActive()
     {
-        StringBuilder result = new StringBuilder();
-        for (Annotation annotation : transactionBeanEntry.getQualifiers())
+        try
         {
-            if (result.length() != 0)
-            {
-                result.append(";");
-            }
-
-            result.append(annotation.annotationType().getName());
+            return getBeanStorage().getActiveTransactionContext() != null;
         }
-        return result.toString();
-    }
-
-    private List<Map<Contextual, TransactionBeanEntry>> getTransactionBeanEntryMaps()
-    {
-        TransactionBeanStorage transactionBeanStorage = TransactionBeanStorage.getStorage();
-
-        if (transactionBeanStorage != null)
+        catch (ContextNotActiveException e)
         {
-            transactionBeanStorage.activateTransactionScope(null);
-            return transactionBeanStorage.getActiveTransactionContextList();
+            return false;
         }
-        return null;
     }
 
-    public Class<? extends Annotation> getScope()
+    private TransactionBeanStorage getBeanStorage()
     {
-        return TransactionScoped.class;
+        if (beanStorage == null)
+        {
+            synchronized (this)
+            {
+                beanStorage = BeanProvider.getContextualReference(TransactionBeanStorage.class);
+            }
+        }
+        return beanStorage;
     }
 
-    public boolean isActive()
-    {
-        return TransactionBeanStorage.getStorage() != null;
-    }
 }