]
Scott Marlow commented on WFLY-2504:
------------------------------------
Just to be clear, WFLY-2504 is a request to implement a non-standard (extension) that is
not required by the JPA specification.
In the description, we mention that we already support both shallow + deep extended
persistence context inheritance. The default is "shallow", which matches the
behaviour described by the JPA specification lead (in a conversation on the JPA 2.1 spec
expert group mailing list).
I believe that the WFLY-2504 extension would be a "lazy" variation of the deep
XPC inheritance (as mentioned in the description).
add lazy xpc inheritance to handle legacy case, remote client with
UserTransaction fails on 2nd SFSB invocation when using extended persistence context
-------------------------------------------------------------------------------------------------------------------------------------------------------
Key: WFLY-2504
URL:
https://issues.jboss.org/browse/WFLY-2504
Project: WildFly
Issue Type: Enhancement
Components: JPA / Hibernate
Reporter: Scott Marlow
Assignee: Scott Marlow
AS5 allowed a remote client to instantiate a set of stateful session beans (e.g. SFSB1 +
SFSB2) and then call the remote stateful session beans (SFSB1+SFSB2) in a started user
transaction (UT1). Each of the stateful beans reference the same extended persistence
context by name. In AS5, both stateful beans will share the same extended persistence
unit context but on AS7/WF8, each bean has its own extended persistence unit context.
Having both XPCS involved in the same user transaction, causes an (EJBException:
JBAS011437: Found extended persistence context in SFSB invocation call stack but that
cannot be used because the transaction already has a transactional context associated with
it...) error to be thrown.
On AS7/WF8, Allow the separate (remote) stateful beans to share the same persistence
context.
One approach might be to defer creation of the extended persistence context until the
first invocation (need to verify that this is the right approach).
Currently, we support shallow + deep extended persistence context inheritance. This will
be a "lazy" variation of the deep XPC inheritance.
Some of the AS5 code is pasted below for easy reference.
{code}
public class ExtendedPersistenceContextPropagationInterceptor implements Interceptor
{
private static final Logger log =
Logger.getLogger(ExtendedPersistenceContextPropagationInterceptor.class);
public String getName()
{
return this.getClass().getName();
}
public Object invoke(Invocation invocation) throws Throwable
{
log.debug("++++ LongLivedSessionPropagationInterceptor");
StatefulContainerInvocation ejb = (StatefulContainerInvocation) invocation;
StatefulBeanContext ctx = (StatefulBeanContext) ejb.getBeanContext();
Map<String, EntityManager> extendedPCs =
ctx.getExtendedPersistenceContexts();
if (extendedPCs == null || extendedPCs.size() == 0)
{
return invocation.invokeNext();
}
TransactionManager tm = TxUtil.getTransactionManager();
if (tm.getTransaction() != null)
{
for (String kernelname : extendedPCs.keySet())
{
EntityManager manager = extendedPCs.get(kernelname);
ManagedEntityManagerFactory factory =
ManagedEntityManagerFactoryHelper.getManagedEntityManagerFactory(kernelname);
factory.registerExtendedWithTransaction(manager);
}
}
return invocation.invokeNext();
}
}
{code}
{code}
public class EJB3XPCResolver implements XPCResolver
{
private static final Logger log = Logger.getLogger(EJB3XPCResolver.class);
/**
* Query the current stateful bean contexts for the specified XPC.
*/
public EntityManager getExtendedPersistenceContext(String kernelName)
{
StatefulBeanContext beanContext = StatefulBeanContext.currentBean.get();
if (beanContext != null)
{
EntityManager em = null;
em = beanContext.getExtendedPersistenceContext(kernelName);
if (em != null) {
log.info("current SFSB has XPC with scoped pu name=" + kernelName +
" on SFSB bean=" + beanContext.getContainer().getIdentifier() +
beanContext.getId());
return em;
}
/**
* Look for XPC in current bean set.
*/
log.info("looking for existing XPC with scoped pu name=" +
kernelName);
List <StatefulBeanContext> beanContexts =
StatefulBeanContext.currentBean.getList();
for( StatefulBeanContext bc : beanContexts)
{
em = bc.getExtendedPersistenceContext(kernelName);
if (em != null) {
log.info("found existing XPC with scoped pu name=" + kernelName
+ " on SFSB bean=" + bc.getContainer().getIdentifier() + bc.getId());
// Propagate created XPC as required (7.6.2.1 Inheritance of Extended
Persistence Context
beanContext.addExtendedPersistenceContext(kernelName, em);
return em;
}
log.info("XPC not found yet, scoped pu name=" + kernelName + "
not in SFSB bean=" + bc.getContainer().getIdentifier() + bc.getId());
}
}
log.info("XPC not found scoped, search done, pu name=" + kernelName);
return null;
}
@Override
public EntityManager createExtendedPersistenceContext(String kernelName)
{
StatefulBeanContext beanContext = StatefulBeanContext.currentBean.get();
if (beanContext != null)
{
EntityManager em = null;
ManagedEntityManagerFactory factory=
((PersistenceUnitDeployment)
PersistenceUnitRegistry.getPersistenceUnit(kernelName)).getManagedFactory();
if (factory != null)
{
em = factory.createEntityManager();
if (em != null)
{
beanContext.addExtendedPersistenceContext(factory.getKernelName(), em);
log.info("created new XPC with scoped pu name=" + kernelName +
" on SFSB bean=" + beanContext.getContainer().getIdentifier() +
beanContext.getId());
/**
* TODO: Propagate created XPC as required (7.6.2.1 Inheritance of
Extended Persistence Context
*
*/
// List <StatefulBeanContext> beanContexts =
StatefulBeanContext.currentBean.getList();
// for( StatefulBeanContext bc : beanContexts)
// {
// bc.addExtendedPersistenceContext(kernelName, em);
// }
}
}
return em;
}
return null;
}
}
{code}
{code}
public class ManagedEntityManagerFactoryHelper
{
public static ManagedEntityManagerFactory getManagedEntityManagerFactory(String
kernelName)
{
PersistenceUnitDeployment pu = (PersistenceUnitDeployment)
PersistenceUnitRegistry.getPersistenceUnit(kernelName);
if(pu != null)
return pu.getManagedFactory();
return null;
}
}
{code}