You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@deltaspike.apache.org by Gerhard Petracek <gp...@apache.org> on 2014/02/27 20:41:54 UTC

Re: git commit: DELTASPIKE-420 Repository integration with TransactionStrategy

@thomas:

with that you have an overhead (in EntityManagerHolder: proxy due to
@ApplicationScoped + ThreadLocal) which is just useful for users of the
ds-data module.
-> if you would like to keep it that way, please use a specialized bean in
the ds-data module and avoid the overhead in the jpa-module.

regards,
gerhard



2014-02-27 19:55 GMT+01:00 <th...@apache.org>:

> Repository: deltaspike
> Updated Branches:
>   refs/heads/master 303507d6b -> db37a83a2
>
>
> DELTASPIKE-420 Repository integration with TransactionStrategy
>
>
> Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo
> Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/db37a83a
> Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/db37a83a
> Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/db37a83a
>
> Branch: refs/heads/master
> Commit: db37a83a2cdd44cde147e6f9926c63e80422c5c6
> Parents: 303507d
> Author: Thomas Hug <Th...@ctp.com>
> Authored: Wed Feb 19 08:34:58 2014 +0100
> Committer: Thomas Hug <Th...@ctp.com>
> Committed: Thu Feb 27 09:49:48 2014 +0100
>
> ----------------------------------------------------------------------
>  deltaspike/modules/data/impl/pom.xml            |  12 ++
>  .../data/impl/builder/DelegateQueryBuilder.java |  21 +---
>  .../impl/handler/CdiQueryInvocationContext.java |   5 +
>  .../impl/handler/EntityRepositoryHandler.java   |   8 ++
>  .../data/impl/handler/QueryHandler.java         |  32 +----
>  .../data/impl/handler/QueryRunner.java          |  28 +++++
>  .../data/impl/meta/RepositoryMethod.java        |  12 ++
>  .../data/impl/meta/RequiresTransaction.java     |  31 +++++
>  .../data/impl/tx/InvocationContextWrapper.java  |  74 +++++++++++
>  .../data/impl/tx/TransactionalQueryRunner.java  |  94 ++++++++++++++
>  .../deltaspike/data/impl/util/ClassUtils.java   |  46 +++++++
>  .../deltaspike/data/impl/util/ProxyUtils.java   |  53 ++++++++
>  .../impl/tx/TransactionalQueryRunnerTest.java   | 123 +++++++++++++++++++
>  .../tx/TransactionalQueryRunnerWrapper.java     |  65 ++++++++++
>  .../service/ExtendedRepositoryInterface.java    |  14 +++
>  .../data/test/util/TestDeployments.java         |  24 +++-
>  .../impl/entitymanager/EntityManagerHolder.java |  49 ++++++++
>  .../ResourceLocalTransactionStrategy.java       |  38 ++++--
>  18 files changed, 667 insertions(+), 62 deletions(-)
> ----------------------------------------------------------------------
>
>
>
> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/db37a83a/deltaspike/modules/data/impl/pom.xml
> ----------------------------------------------------------------------
> diff --git a/deltaspike/modules/data/impl/pom.xml
> b/deltaspike/modules/data/impl/pom.xml
> index 7b262fb..f54bef6 100755
> --- a/deltaspike/modules/data/impl/pom.xml
> +++ b/deltaspike/modules/data/impl/pom.xml
> @@ -113,6 +113,12 @@
>              <artifactId>deltaspike-partial-bean-module-impl</artifactId>
>              <scope>runtime</scope>
>          </dependency>
> +
> +        <dependency>
> +            <groupId>org.apache.deltaspike.modules</groupId>
> +            <artifactId>deltaspike-jpa-module-impl</artifactId>
> +            <scope>compile</scope>
> +        </dependency>
>
>          <!-- Tests -->
>
> @@ -121,6 +127,12 @@
>              <artifactId>shrinkwrap-resolver-impl-maven</artifactId>
>              <scope>test</scope>
>          </dependency>
> +
> +        <dependency>
> +            <groupId>org.jboss.shrinkwrap.descriptors</groupId>
> +            <artifactId>shrinkwrap-descriptors-impl-javaee</artifactId>
> +            <scope>test</scope>
> +        </dependency>
>
>      </dependencies>
>
>
>
> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/db37a83a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/DelegateQueryBuilder.java
> ----------------------------------------------------------------------
> diff --git
> a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/DelegateQueryBuilder.java
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/DelegateQueryBuilder.java
> index 0668ce7..1d9ca5d 100644
> ---
> a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/DelegateQueryBuilder.java
> +++
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/DelegateQueryBuilder.java
> @@ -18,6 +18,9 @@
>   */
>  package org.apache.deltaspike.data.impl.builder;
>
> +import static org.apache.deltaspike.data.impl.util.ClassUtils.contains;
> +import static org.apache.deltaspike.data.impl.util.ClassUtils.extract;
> +
>  import java.lang.reflect.InvocationTargetException;
>  import java.lang.reflect.Method;
>  import java.util.Set;
> @@ -87,24 +90,6 @@ public class DelegateQueryBuilder extends QueryBuilder
>          return null;
>      }
>
> -    private boolean contains(Class<?> obj, Method method)
> -    {
> -        return extract(obj, method) != null;
> -    }
> -
> -    private Method extract(Class<?> obj, Method method)
> -    {
> -        try
> -        {
> -            String name = method.getName();
> -            return obj != null ? obj.getMethod(name,
> method.getParameterTypes()) : null;
> -        }
> -        catch (NoSuchMethodException e)
> -        {
> -            return null;
> -        }
> -    }
> -
>      private Object invoke(DelegateQueryHandler delegate,
> CdiQueryInvocationContext context)
>      {
>          try
>
>
> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/db37a83a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java
> ----------------------------------------------------------------------
> diff --git
> a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java
> index 8900d68..d553114 100644
> ---
> a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java
> +++
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java
> @@ -226,4 +226,9 @@ public class CdiQueryInvocationContext implements
> QueryInvocationContext
>          return repoMethod.getSingleResultStyle();
>      }
>
> +    public Object getProxy()
> +    {
> +        return proxy;
> +    }
> +
>  }
>
>
> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/db37a83a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/EntityRepositoryHandler.java
> ----------------------------------------------------------------------
> diff --git
> a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/EntityRepositoryHandler.java
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/EntityRepositoryHandler.java
> index 709d733..0c6ce40 100755
> ---
> a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/EntityRepositoryHandler.java
> +++
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/EntityRepositoryHandler.java
> @@ -37,6 +37,7 @@ import javax.persistence.metamodel.SingularAttribute;
>
>  import org.apache.deltaspike.data.api.EntityRepository;
>  import org.apache.deltaspike.data.impl.builder.QueryBuilder;
> +import org.apache.deltaspike.data.impl.meta.RequiresTransaction;
>  import org.apache.deltaspike.data.impl.property.Property;
>  import
> org.apache.deltaspike.data.impl.property.query.NamedPropertyCriteria;
>  import org.apache.deltaspike.data.impl.property.query.PropertyQueries;
> @@ -59,6 +60,7 @@ public class EntityRepositoryHandler<E, PK extends
> Serializable>
>      private QueryInvocationContext context;
>
>      @Override
> +    @RequiresTransaction
>      public E save(E entity)
>      {
>          if (context.isNew(entity))
> @@ -70,6 +72,7 @@ public class EntityRepositoryHandler<E, PK extends
> Serializable>
>      }
>
>      @Override
> +    @RequiresTransaction
>      public E saveAndFlush(E entity)
>      {
>          E result = save(entity);
> @@ -78,6 +81,7 @@ public class EntityRepositoryHandler<E, PK extends
> Serializable>
>      }
>
>      @Override
> +    @RequiresTransaction
>      public E saveAndFlushAndRefresh(E entity)
>      {
>          E result = saveAndFlush(entity);
> @@ -86,6 +90,7 @@ public class EntityRepositoryHandler<E, PK extends
> Serializable>
>      }
>
>      @Override
> +    @RequiresTransaction
>      public void refresh(E entity)
>      {
>          entityManager().refresh(entity);
> @@ -161,12 +166,14 @@ public class EntityRepositoryHandler<E, PK extends
> Serializable>
>      }
>
>      @Override
> +    @RequiresTransaction
>      public void remove(E entity)
>      {
>          entityManager().remove(entity);
>      }
>
>      @Override
> +    @RequiresTransaction
>      public void removeAndFlush(E entity)
>      {
>          entityManager().remove(entity);
> @@ -174,6 +181,7 @@ public class EntityRepositoryHandler<E, PK extends
> Serializable>
>      }
>
>      @Override
> +    @RequiresTransaction
>      public void flush()
>      {
>          entityManager().flush();
>
>
> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/db37a83a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/QueryHandler.java
> ----------------------------------------------------------------------
> diff --git
> a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/QueryHandler.java
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/QueryHandler.java
> index 6ce2af8..4a0ecd0 100755
> ---
> a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/QueryHandler.java
> +++
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/QueryHandler.java
> @@ -18,12 +18,11 @@
>   */
>  package org.apache.deltaspike.data.impl.handler;
>
> +import static
> org.apache.deltaspike.data.impl.util.ProxyUtils.extractFromProxy;
> +
>  import java.io.Serializable;
>  import java.lang.reflect.InvocationHandler;
>  import java.lang.reflect.Method;
> -import java.lang.reflect.Proxy;
> -import java.util.Arrays;
> -import java.util.LinkedList;
>  import java.util.List;
>  import java.util.logging.Level;
>  import java.util.logging.Logger;
> @@ -64,6 +63,9 @@ public class QueryHandler implements Serializable,
> InvocationHandler
>      @Inject
>      private EntityManagerLookup entityManagerLookup;
>
> +    @Inject
> +    private QueryRunner runner;
> +
>      @Override
>      public Object invoke(Object proxy, Method method, Object[] args)
> throws Throwable
>      {
> @@ -75,7 +77,7 @@ public class QueryHandler implements Serializable,
> InvocationHandler
>              RepositoryMethod repoMethod =
> components.lookupMethod(repo.getRepositoryClass(), method);
>              queryContext = createContext(proxy, method, args, repo,
> repoMethod);
>              QueryBuilder builder = queryBuilder.build(repoMethod,
> queryContext);
> -            Object result = builder.executeQuery(queryContext);
> +            Object result = runner.executeQuery(builder, queryContext);
>              return result;
>          }
>          catch (PersistenceException e)
> @@ -107,26 +109,4 @@ public class QueryHandler implements Serializable,
> InvocationHandler
>          return queryContext;
>      }
>
> -    protected List<Class<?>> extractFromProxy(Class<?> proxyClass)
> -    {
> -        List<Class<?>> result = new LinkedList<Class<?>>();
> -        result.add(proxyClass);
> -        if (isInterfaceProxy(proxyClass))
> -        {
> -            result.addAll(Arrays.asList(proxyClass.getInterfaces()));
> -        }
> -        else
> -        {
> -            result.add(proxyClass.getSuperclass());
> -        }
> -        return result;
> -    }
> -
> -    private boolean isInterfaceProxy(Class<?> proxyClass)
> -    {
> -        Class<?>[] interfaces = proxyClass.getInterfaces();
> -        return Proxy.class.equals(proxyClass.getSuperclass()) &&
> -                interfaces != null && interfaces.length > 0;
> -    }
> -
>  }
>
>
> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/db37a83a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/QueryRunner.java
> ----------------------------------------------------------------------
> diff --git
> a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/QueryRunner.java
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/QueryRunner.java
> new file mode 100644
> index 0000000..a0f9206
> --- /dev/null
> +++
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/QueryRunner.java
> @@ -0,0 +1,28 @@
> +/*
> + * 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.data.impl.handler;
> +
> +import org.apache.deltaspike.data.impl.builder.QueryBuilder;
> +
> +public interface QueryRunner
> +{
> +
> +    Object executeQuery(QueryBuilder builder, CdiQueryInvocationContext
> context) throws Throwable;
> +
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/db37a83a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java
> ----------------------------------------------------------------------
> diff --git
> a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java
> index ac90562..ff051fe 100644
> ---
> a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java
> +++
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java
> @@ -27,10 +27,12 @@ import java.util.Set;
>
>  import javax.enterprise.inject.spi.Bean;
>  import javax.enterprise.inject.spi.BeanManager;
> +import javax.persistence.LockModeType;
>
>  import org.apache.deltaspike.core.api.provider.BeanManagerProvider;
>  import org.apache.deltaspike.core.api.provider.BeanProvider;
>  import org.apache.deltaspike.core.api.provider.DependentProvider;
> +import org.apache.deltaspike.data.api.Modifying;
>  import org.apache.deltaspike.data.api.Query;
>  import org.apache.deltaspike.data.api.SingleResultType;
>  import org.apache.deltaspike.data.api.mapping.MappingConfig;
> @@ -230,4 +232,14 @@ public class RepositoryMethod
>          return methodPrefix.getSingleResultStyle();
>      }
>
> +    public boolean requiresTransaction()
> +    {
> +        boolean hasLockMode = false;
> +        if (method.isAnnotationPresent(Query.class))
> +        {
> +            hasLockMode =
> !method.getAnnotation(Query.class).lock().equals(LockModeType.NONE);
> +        }
> +        return hasLockMode || method.isAnnotationPresent(Modifying.class);
> +    }
> +
>  }
>
>
> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/db37a83a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RequiresTransaction.java
> ----------------------------------------------------------------------
> diff --git
> a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RequiresTransaction.java
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RequiresTransaction.java
> new file mode 100644
> index 0000000..c59593e
> --- /dev/null
> +++
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RequiresTransaction.java
> @@ -0,0 +1,31 @@
> +/*
> + * 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.data.impl.meta;
> +
> +import static java.lang.annotation.ElementType.METHOD;
> +import static java.lang.annotation.RetentionPolicy.RUNTIME;
> +
> +import java.lang.annotation.Retention;
> +import java.lang.annotation.Target;
> +
> +@Target(METHOD)
> +@Retention(RUNTIME)
> +public @interface RequiresTransaction
> +{
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/db37a83a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/tx/InvocationContextWrapper.java
> ----------------------------------------------------------------------
> diff --git
> a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/tx/InvocationContextWrapper.java
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/tx/InvocationContextWrapper.java
> new file mode 100644
> index 0000000..e8692cb
> --- /dev/null
> +++
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/tx/InvocationContextWrapper.java
> @@ -0,0 +1,74 @@
> +/*
> + * 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.data.impl.tx;
> +
> +import java.lang.reflect.Method;
> +import java.util.HashMap;
> +import java.util.Map;
> +
> +import javax.interceptor.InvocationContext;
> +
> +import org.apache.deltaspike.data.impl.handler.CdiQueryInvocationContext;
> +
> +public abstract class InvocationContextWrapper implements
> InvocationContext
> +{
> +
> +    private final CdiQueryInvocationContext context;
> +
> +    public InvocationContextWrapper(CdiQueryInvocationContext context)
> +    {
> +        this.context = context;
> +    }
> +
> +    @Override
> +    public Map<String, Object> getContextData()
> +    {
> +        return new HashMap<String, Object>(0);
> +    }
> +
> +    @Override
> +    public Method getMethod()
> +    {
> +        return context.getMethod();
> +    }
> +
> +    @Override
> +    public Object[] getParameters()
> +    {
> +        return context.getMethodParameters();
> +    }
> +
> +    @Override
> +    public Object getTarget()
> +    {
> +        return context.getProxy();
> +    }
> +
> +    @Override
> +    public Object getTimer()
> +    {
> +        return null;
> +    }
> +
> +    @Override
> +    public void setParameters(Object[] args)
> +    {
> +    }
> +
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/db37a83a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/tx/TransactionalQueryRunner.java
> ----------------------------------------------------------------------
> diff --git
> a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/tx/TransactionalQueryRunner.java
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/tx/TransactionalQueryRunner.java
> new file mode 100644
> index 0000000..d1b7d00
> --- /dev/null
> +++
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/tx/TransactionalQueryRunner.java
> @@ -0,0 +1,94 @@
> +/*
> + * 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.data.impl.tx;
> +
> +import static org.apache.deltaspike.data.impl.util.ClassUtils.contains;
> +import static org.apache.deltaspike.data.impl.util.ClassUtils.extract;
> +
> +import java.lang.reflect.Method;
> +
> +import javax.inject.Inject;
> +
> +import org.apache.deltaspike.data.impl.builder.QueryBuilder;
> +import org.apache.deltaspike.data.impl.handler.CdiQueryInvocationContext;
> +import org.apache.deltaspike.data.impl.handler.EntityRepositoryHandler;
> +import org.apache.deltaspike.data.impl.handler.QueryRunner;
> +import org.apache.deltaspike.data.impl.meta.RequiresTransaction;
> +import org.apache.deltaspike.jpa.impl.entitymanager.EntityManagerHolder;
> +import org.apache.deltaspike.jpa.spi.transaction.TransactionStrategy;
> +
> +public class TransactionalQueryRunner implements QueryRunner
> +{
> +
> +    @Inject
> +    private TransactionStrategy strategy;
> +
> +    @Inject
> +    private EntityManagerHolder entityManagerHolder;
> +
> +    @Override
> +    public Object executeQuery(final QueryBuilder builder, final
> CdiQueryInvocationContext context)
> +        throws Throwable
> +    {
> +        if (needsTransaction(context))
> +        {
> +            try
> +            {
> +                entityManagerHolder.set(context.getEntityManager());
> +                return executeTransactional(builder, context);
> +            }
> +            finally
> +            {
> +                entityManagerHolder.dispose();
> +            }
> +        }
> +        return executeNonTransactional(builder, context);
> +    }
> +
> +    protected Object executeNonTransactional(final QueryBuilder builder,
> final CdiQueryInvocationContext context)
> +    {
> +        return builder.executeQuery(context);
> +    }
> +
> +    protected Object executeTransactional(final QueryBuilder builder,
> final CdiQueryInvocationContext context)
> +        throws Exception
> +    {
> +        return strategy.execute(new InvocationContextWrapper(context)
> +        {
> +            @Override
> +            public Object proceed() throws Exception
> +            {
> +                return builder.executeQuery(context);
> +            }
> +        });
> +    }
> +
> +    private boolean needsTransaction(CdiQueryInvocationContext context)
> +    {
> +        boolean requiresTx = false;
> +        Method method = context.getMethod();
> +        if (contains(EntityRepositoryHandler.class, method))
> +        {
> +            Method executed = extract(EntityRepositoryHandler.class,
> method);
> +            requiresTx =
> executed.isAnnotationPresent(RequiresTransaction.class);
> +        }
> +        return requiresTx ||
> context.getRepositoryMethod().requiresTransaction();
> +    }
> +
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/db37a83a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/ClassUtils.java
> ----------------------------------------------------------------------
> diff --git
> a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/ClassUtils.java
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/ClassUtils.java
> new file mode 100644
> index 0000000..d1e73ff
> --- /dev/null
> +++
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/ClassUtils.java
> @@ -0,0 +1,46 @@
> +/*
> + * 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.data.impl.util;
> +
> +import java.lang.reflect.Method;
> +
> +public class ClassUtils
> +{
> +    private ClassUtils()
> +    {
> +    }
> +
> +    public static boolean contains(Class<?> obj, Method method)
> +    {
> +        return extract(obj, method) != null;
> +    }
> +
> +    public static Method extract(Class<?> clazz, Method method)
> +    {
> +        try
> +        {
> +            String name = method.getName();
> +            return clazz != null ? clazz.getMethod(name,
> method.getParameterTypes()) : null;
> +        }
> +        catch (NoSuchMethodException e)
> +        {
> +            return null;
> +        }
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/db37a83a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/ProxyUtils.java
> ----------------------------------------------------------------------
> diff --git
> a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/ProxyUtils.java
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/ProxyUtils.java
> new file mode 100644
> index 0000000..d683e32
> --- /dev/null
> +++
> b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/ProxyUtils.java
> @@ -0,0 +1,53 @@
> +/*
> + * 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.data.impl.util;
> +
> +import java.lang.reflect.Proxy;
> +import java.util.Arrays;
> +import java.util.LinkedList;
> +import java.util.List;
> +
> +public class ProxyUtils
> +{
> +    private ProxyUtils()
> +    {
> +    }
> +
> +    public static List<Class<?>> extractFromProxy(Class<?> proxyClass)
> +    {
> +        List<Class<?>> result = new LinkedList<Class<?>>();
> +        result.add(proxyClass);
> +        if (isInterfaceProxy(proxyClass))
> +        {
> +            result.addAll(Arrays.asList(proxyClass.getInterfaces()));
> +        }
> +        else
> +        {
> +            result.add(proxyClass.getSuperclass());
> +        }
> +        return result;
> +    }
> +
> +    public static boolean isInterfaceProxy(Class<?> proxyClass)
> +    {
> +        Class<?>[] interfaces = proxyClass.getInterfaces();
> +        return Proxy.class.equals(proxyClass.getSuperclass()) &&
> +                interfaces != null && interfaces.length > 0;
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/db37a83a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/tx/TransactionalQueryRunnerTest.java
> ----------------------------------------------------------------------
> diff --git
> a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/tx/TransactionalQueryRunnerTest.java
> b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/tx/TransactionalQueryRunnerTest.java
> new file mode 100644
> index 0000000..c6c7346
> --- /dev/null
> +++
> b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/tx/TransactionalQueryRunnerTest.java
> @@ -0,0 +1,123 @@
> +/*
> + * 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.data.impl.tx;
> +
> +import static org.junit.Assert.assertNotNull;
> +import static org.junit.Assert.assertTrue;
> +
> +import javax.enterprise.inject.Produces;
> +import javax.inject.Inject;
> +import javax.persistence.EntityManager;
> +import javax.persistence.PersistenceContext;
> +
> +import org.apache.deltaspike.data.test.domain.Simple;
> +import
> org.apache.deltaspike.data.test.service.ExtendedRepositoryInterface;
> +import org.apache.deltaspike.data.test.util.TestDeployments;
> +import org.apache.deltaspike.test.category.WebProfileCategory;
> +import org.jboss.arquillian.container.test.api.Deployment;
> +import org.jboss.arquillian.junit.Arquillian;
> +import org.jboss.arquillian.junit.InSequence;
> +import org.jboss.shrinkwrap.api.Archive;
> +import org.junit.Before;
> +import org.junit.Test;
> +import org.junit.experimental.categories.Category;
> +import org.junit.runner.RunWith;
> +
> +@Category(WebProfileCategory.class)
> +@RunWith(Arquillian.class)
> +public class TransactionalQueryRunnerTest
> +{
> +
> +    private static final String NAME = "should_run_in_transaction";
> +
> +    @Deployment
> +    public static Archive<?> deployment()
> +    {
> +        return TestDeployments.initDeployment()
> +                .addClasses(ExtendedRepositoryInterface.class)
> +                .addPackage(Simple.class.getPackage());
> +    }
> +
> +    @Inject
> +    private ExtendedRepositoryInterface repository;
> +
> +    @Produces
> +    @PersistenceContext
> +    private EntityManager entityManager;
> +
> +    @Inject
> +    private TransactionalQueryRunnerWrapper wrapper;
> +
> +    @Test
> +    @InSequence(1)
> +    public void should_run_modifying_in_transaction() throws Exception
> +    {
> +        // when
> +        repository.deleteAll();
> +
> +        // then
> +        assertTrue(wrapper.isRunInTx());
> +    }
> +
> +    @Test
> +    @InSequence(2)
> +    public void should_save_in_transaction() throws Exception
> +    {
> +        // given
> +        Simple simple = new Simple(NAME);
> +
> +        // when
> +        simple = repository.save(simple);
> +
> +        // then
> +        assertNotNull(simple.getId());
> +        assertTrue(wrapper.isRunInTx());
> +    }
> +
> +    @Test
> +    @InSequence(3)
> +    public void should_find_with_lockmode_in_transaction() throws
> Exception
> +    {
> +        // when
> +        Simple simple = repository.findByName(NAME);
> +
> +        // then
> +        assertNotNull(simple);
> +        assertTrue(wrapper.isRunInTx());
> +    }
> +
> +    @Test
> +    @InSequence(4)
> +    public void should_find_no_lock_without_transaction() throws Exception
> +    {
> +        // when
> +        Simple simple = repository.findByNameNoLock(NAME);
> +
> +        // then
> +        assertNotNull(simple);
> +        assertTrue(wrapper.isRunInNonTx());
> +    }
> +
> +    @Before
> +    public void init()
> +    {
> +        wrapper.reset();
> +    }
> +
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/db37a83a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/tx/TransactionalQueryRunnerWrapper.java
> ----------------------------------------------------------------------
> diff --git
> a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/tx/TransactionalQueryRunnerWrapper.java
> b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/tx/TransactionalQueryRunnerWrapper.java
> new file mode 100644
> index 0000000..14e0e63
> --- /dev/null
> +++
> b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/tx/TransactionalQueryRunnerWrapper.java
> @@ -0,0 +1,65 @@
> +/*
> + * 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.data.impl.tx;
> +
> +import javax.enterprise.context.ApplicationScoped;
> +import javax.enterprise.inject.Specializes;
> +
> +import org.apache.deltaspike.data.impl.builder.QueryBuilder;
> +import org.apache.deltaspike.data.impl.handler.CdiQueryInvocationContext;
> +
> +@Specializes
> +@ApplicationScoped
> +public class TransactionalQueryRunnerWrapper extends
> TransactionalQueryRunner
> +{
> +
> +    private boolean runInTx = false;
> +    private boolean runInNonTx = false;
> +
> +    public void reset()
> +    {
> +        runInTx = false;
> +        runInNonTx = false;
> +    }
> +
> +    @Override
> +    protected Object executeNonTransactional(QueryBuilder builder,
> CdiQueryInvocationContext context)
> +    {
> +        runInNonTx = true;
> +        return super.executeNonTransactional(builder, context);
> +    }
> +
> +    @Override
> +    protected Object executeTransactional(QueryBuilder builder,
> CdiQueryInvocationContext context) throws Exception
> +    {
> +        runInTx = true;
> +        return super.executeTransactional(builder, context);
> +    }
> +
> +    public boolean isRunInTx()
> +    {
> +        return runInTx;
> +    }
> +
> +    public boolean isRunInNonTx()
> +    {
> +        return runInNonTx;
> +    }
> +
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/db37a83a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/service/ExtendedRepositoryInterface.java
> ----------------------------------------------------------------------
> diff --git
> a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/service/ExtendedRepositoryInterface.java
> b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/service/ExtendedRepositoryInterface.java
> index 49ab7f4..1445d33 100755
> ---
> a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/service/ExtendedRepositoryInterface.java
> +++
> b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/service/ExtendedRepositoryInterface.java
> @@ -18,11 +18,25 @@
>   */
>  package org.apache.deltaspike.data.test.service;
>
> +import static javax.persistence.LockModeType.PESSIMISTIC_READ;
> +
>  import org.apache.deltaspike.data.api.EntityRepository;
> +import org.apache.deltaspike.data.api.Modifying;
> +import org.apache.deltaspike.data.api.Query;
>  import org.apache.deltaspike.data.api.Repository;
>  import org.apache.deltaspike.data.test.domain.Simple;
>
>  @Repository
>  public interface ExtendedRepositoryInterface extends
> EntityRepository<Simple, Long>
>  {
> +
> +    @Query(lock = PESSIMISTIC_READ)
> +    Simple findByName(String name);
> +
> +    @Query(named = Simple.BY_NAME_LIKE)
> +    Simple findByNameNoLock(String name);
> +
> +    @Modifying @Query("delete from Simple")
> +    int deleteAll();
> +
>  }
>
>
> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/db37a83a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/util/TestDeployments.java
> ----------------------------------------------------------------------
> diff --git
> a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/util/TestDeployments.java
> b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/util/TestDeployments.java
> index d002913..0472a40 100755
> ---
> a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/util/TestDeployments.java
> +++
> b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/util/TestDeployments.java
> @@ -47,13 +47,16 @@ import
> org.apache.deltaspike.data.impl.builder.QueryBuilder;
>  import org.apache.deltaspike.data.impl.criteria.QueryCriteria;
>  import org.apache.deltaspike.data.impl.handler.QueryHandler;
>  import org.apache.deltaspike.data.impl.meta.RepositoryComponents;
> +import org.apache.deltaspike.data.impl.meta.RequiresTransaction;
>  import org.apache.deltaspike.data.impl.param.Parameters;
>  import org.apache.deltaspike.data.impl.property.Property;
> +import org.apache.deltaspike.data.impl.tx.TransactionalQueryRunner;
>  import org.apache.deltaspike.data.impl.util.EntityUtils;
>  import org.apache.deltaspike.data.spi.DelegateQueryHandler;
>  import org.apache.deltaspike.data.spi.QueryInvocationContext;
>  import org.apache.deltaspike.data.test.TransactionalTestCase;
>  import org.apache.deltaspike.data.test.domain.AuditedEntity;
> +import
> org.apache.deltaspike.jpa.impl.transaction.EnvironmentAwareTransactionStrategy;
>  import org.apache.deltaspike.test.category.WebProfileCategory;
>  import org.apache.deltaspike.test.utils.CdiContainerUnderTest;
>  import org.jboss.shrinkwrap.api.Archive;
> @@ -61,9 +64,11 @@ import org.jboss.shrinkwrap.api.ArchivePath;
>  import org.jboss.shrinkwrap.api.ArchivePaths;
>  import org.jboss.shrinkwrap.api.Filter;
>  import org.jboss.shrinkwrap.api.ShrinkWrap;
> -import org.jboss.shrinkwrap.api.asset.EmptyAsset;
> +import org.jboss.shrinkwrap.api.asset.StringAsset;
>  import org.jboss.shrinkwrap.api.spec.JavaArchive;
>  import org.jboss.shrinkwrap.api.spec.WebArchive;
> +import org.jboss.shrinkwrap.descriptor.api.Descriptors;
> +import org.jboss.shrinkwrap.descriptor.api.beans10.BeansDescriptor;
>  import org.jboss.shrinkwrap.impl.base.filter.ExcludeRegExpPaths;
>  import org.jboss.shrinkwrap.resolver.api.maven.Maven;
>
> @@ -85,6 +90,12 @@ public abstract class TestDeployments
>      public static WebArchive initDeployment(String testFilter)
>      {
>          Logging.reconfigure();
> +        String descriptor = Descriptors.create(BeansDescriptor.class)
> +                .addDefaultNamespaces()
> +                .createAlternatives()
> +
>  .clazz(EnvironmentAwareTransactionStrategy.class.getName())
> +                    .up()
> +                .exportAsString();
>          WebArchive archive = ShrinkWrap
>                  .create(WebArchive.class, "test.war")
>                  .addAsLibrary(createApiArchive())
> @@ -98,7 +109,7 @@ public abstract class TestDeployments
>
>  ArchivePaths.create("classes/META-INF/persistence.xml"))
>
>  .addAsWebInfResource("META-INF/services/javax.enterprise.inject.spi.Extension",
>
>  ArchivePaths.create("classes/META-INF/services/javax.enterprise.inject.spi.Extension"))
> -                .addAsWebInfResource(EmptyAsset.INSTANCE,
> ArchivePaths.create("beans.xml"));
> +                .addAsWebInfResource(new StringAsset(descriptor),
> ArchivePaths.create("beans.xml"));
>
>          return addDependencies(archive);
>      }
> @@ -113,7 +124,8 @@ public abstract class TestDeployments
>                  RepositoryComponents.class.getPackage(),
>                  Parameters.class.getPackage(),
>                  EntityUtils.class.getPackage(),
> -                Property.class.getPackage()
> +                Property.class.getPackage(),
> +                TransactionalQueryRunner.class.getPackage()
>          };
>      }
>
> @@ -128,7 +140,7 @@ public abstract class TestDeployments
>                  .addClasses(Criteria.class, QuerySelection.class,
> CriteriaSupport.class)
>                  .addClasses(CreatedOn.class, CurrentUser.class,
> ModifiedBy.class, ModifiedOn.class)
>                  .addClasses(MappingConfig.class, QueryInOutMapper.class)
> -                .addClasses(DelegateQueryHandler.class,
> QueryInvocationContext.class);
> +                .addClasses(DelegateQueryHandler.class,
> QueryInvocationContext.class, RequiresTransaction.class);
>      }
>
>      public static WebArchive addDependencies(WebArchive archive)
> @@ -138,7 +150,9 @@ public abstract class TestDeployments
>                          "org.apache.deltaspike.core:deltaspike-core-api",
>                          "org.apache.deltaspike.core:deltaspike-core-impl",
>
>  "org.apache.deltaspike.modules:deltaspike-partial-bean-module-api",
> -
>  "org.apache.deltaspike.modules:deltaspike-partial-bean-module-impl")
> +
>  "org.apache.deltaspike.modules:deltaspike-partial-bean-module-impl",
> +
>  "org.apache.deltaspike.modules:deltaspike-jpa-module-api",
> +
>  "org.apache.deltaspike.modules:deltaspike-jpa-module-impl")
>                          .withTransitivity()
>                          .asFile());
>          if (CdiContainerUnderTest.is("owb-.*") ||
>
>
> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/db37a83a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/entitymanager/EntityManagerHolder.java
> ----------------------------------------------------------------------
> diff --git
> a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/entitymanager/EntityManagerHolder.java
> b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/entitymanager/EntityManagerHolder.java
> new file mode 100644
> index 0000000..2d3a5a4
> --- /dev/null
> +++
> b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/entitymanager/EntityManagerHolder.java
> @@ -0,0 +1,49 @@
> +/*
> + * 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.entitymanager;
> +
> +import javax.enterprise.context.ApplicationScoped;
> +import javax.persistence.EntityManager;
> +
> +@ApplicationScoped
> +public class EntityManagerHolder
> +{
> +
> +    private final ThreadLocal<EntityManager> entityManager = new
> ThreadLocal<EntityManager>();
> +
> +    public void set(EntityManager entityManager)
> +    {
> +        this.entityManager.set(entityManager);
> +    }
> +
> +    public boolean isSet()
> +    {
> +        return get() != null;
> +    }
> +
> +    public EntityManager get()
> +    {
> +        return entityManager.get();
> +    }
> +
> +    public void dispose()
> +    {
> +        entityManager.remove();
> +    }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/db37a83a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/ResourceLocalTransactionStrategy.java
> ----------------------------------------------------------------------
> diff --git
> a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/ResourceLocalTransactionStrategy.java
> b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/ResourceLocalTransactionStrategy.java
> index 717206c..d5819ae 100644
> ---
> a/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/ResourceLocalTransactionStrategy.java
> +++
> b/deltaspike/modules/jpa/impl/src/main/java/org/apache/deltaspike/jpa/impl/transaction/ResourceLocalTransactionStrategy.java
> @@ -19,14 +19,15 @@
>  package org.apache.deltaspike.jpa.impl.transaction;
>
>
> -import org.apache.deltaspike.core.api.literal.AnyLiteral;
> -import org.apache.deltaspike.core.util.ProxyUtils;
> -import org.apache.deltaspike.jpa.api.transaction.Transactional;
> -import
> org.apache.deltaspike.jpa.impl.transaction.context.EntityManagerEntry;
> -import
> org.apache.deltaspike.jpa.impl.transaction.context.TransactionBeanStorage;
> -import org.apache.deltaspike.jpa.spi.transaction.TransactionStrategy;
> +import java.lang.annotation.Annotation;
> +import java.util.Arrays;
> +import java.util.HashSet;
> +import java.util.Set;
> +import java.util.logging.Level;
> +import java.util.logging.Logger;
>
>  import javax.enterprise.context.Dependent;
> +import javax.enterprise.inject.Default;
>  import javax.enterprise.inject.spi.Bean;
>  import javax.enterprise.inject.spi.BeanManager;
>  import javax.inject.Inject;
> @@ -34,11 +35,13 @@ import javax.interceptor.InvocationContext;
>  import javax.persistence.EntityManager;
>  import javax.persistence.EntityTransaction;
>
> -import java.lang.annotation.Annotation;
> -import java.util.HashSet;
> -import java.util.Set;
> -import java.util.logging.Level;
> -import java.util.logging.Logger;
> +import org.apache.deltaspike.core.api.literal.AnyLiteral;
> +import org.apache.deltaspike.core.util.ProxyUtils;
> +import org.apache.deltaspike.jpa.api.transaction.Transactional;
> +import org.apache.deltaspike.jpa.impl.entitymanager.EntityManagerHolder;
> +import
> org.apache.deltaspike.jpa.impl.transaction.context.EntityManagerEntry;
> +import
> org.apache.deltaspike.jpa.impl.transaction.context.TransactionBeanStorage;
> +import org.apache.deltaspike.jpa.spi.transaction.TransactionStrategy;
>
>  /**
>   * <p>Default implementation of our plugable TransactionStrategy.
> @@ -70,6 +73,10 @@ public class ResourceLocalTransactionStrategy
> implements TransactionStrategy
>      @Inject
>      private TransactionStrategyHelper transactionHelper;
>
> +    @Inject
> +    private EntityManagerHolder emHolder;
> +
> +    @Override
>      public Object execute(InvocationContext invocationContext) throws
> Exception
>      {
>          Transactional transactionalAnnotation =
> transactionHelper.extractTransactionalAnnotation(invocationContext);
> @@ -77,8 +84,9 @@ public class ResourceLocalTransactionStrategy implements
> TransactionStrategy
>          Class targetClass =
> ProxyUtils.getUnproxiedClass(invocationContext.getTarget().getClass());
> //see DELTASPIKE-517
>
>          // all the configured qualifier keys
> -        Set<Class<? extends Annotation>> emQualifiers =
> transactionHelper.resolveEntityManagerQualifiers(
> -                    transactionalAnnotation, targetClass);
> +        Set<Class<? extends Annotation>> emQualifiers = emHolder.isSet() ?
> +                new HashSet<Class<? extends
> Annotation>>(Arrays.asList(Default.class)) :
> +
>  transactionHelper.resolveEntityManagerQualifiers(transactionalAnnotation,
> targetClass);
>
>          TransactionBeanStorage transactionBeanStorage =
> TransactionBeanStorage.getInstance();
>
> @@ -307,6 +315,10 @@ public class ResourceLocalTransactionStrategy
> implements TransactionStrategy
>
>      private EntityManager resolveEntityManagerForQualifier(Class<?
> extends Annotation> emQualifier)
>      {
> +        if (emHolder.isSet())
> +        {
> +            return emHolder.get();
> +        }
>          Bean<EntityManager> entityManagerBean =
> resolveEntityManagerBean(emQualifier);
>
>          if (entityManagerBean == null)
>
>