Thanks for raising these great questions, I'm interested in the answers also. I also mentioned this forum thread in the persistence forum.
As a developer working on the implementation, I have a few other things to share and ask about. I think that one of the challenges for using extended persistence contexts in your application, is understanding exactly how they work.
When I first started to work on the AS7 support for extended persistence contexts, I used the existing JBoss EJB3 container implementation as a guide but I still had many questions for others. I still continue to ask questions but that is mostly about how we can improve how extended persistence contexts work in your application. Recently, the JPA 2.1 expert group has had some discussion about allowing ways to share the extended persistence context between different beans. Depending on how the below questions are answered, I'd like to put more effort into discussing the proposed changes and an initial JBoss extension for the same (that I hope to get merged into AS soon).
For those that aren't yet using extended persistence contexts in your applications, do you have unanswered questions about how they would work in your application? In the long term, I'd like to document much more about how extended persistence contexts work (current doc is light).
If a stateful bean, references other stateful beans, extended persistence contexts that use the same (persistence unit) name, can be shared. Do any of you share the extended persistence context between different stateful beans? If your not sure, please answer that your not sure (that will be a big hint that we need to better document how extended persistence context inheritance works). The sharing of extended persistence contexts is described in the JPA 2.0 specification as follows:
18.104.22.168 Inheritance of Extended Persistence Context
If a stateful session bean instantiates a stateful session bean (executing in the same EJB container instance) which also has such an extended persistence context, the extended persistence context of the first stateful session bean is inherited by the second stateful session bean and bound to it, and this rule recursively applies—independently of whether transactions are active or not at the point of the creation of the stateful session beans.
If the persistence context has been inherited by any stateful session beans, the container does not close the persistence context until all such stateful session beans have been removed or otherwise destroyed.
We put a lot of effort into figuring out how clustering of extended persistence contexts would work in AS7. If you are clustering your stateful session beans with extended persistence contexts, I'm interesting in reading what your beans look like. I especially want to know if your clustered beans reference other stateful beans that inherit/share the extended persistence context. We have a few tests that cluster a stateful bean that references another stateful bean. The test verifies that a new entity (not saved to the database) is available on both cluster nodes. If the extended persistence context is not properly clustered, the test will fail. If you think that you might want to cluster your stateful beans with extended persistence contexts in the future, please let us know that also.
Scott, thank you for posting - we just need some more users to post now too
It's interesting that you comment on how we struggle to understand how Extended Persistence Contexts work in practise. We've designed our app to not use clustering at all, because I assumed that an extended persistence context would not work across a cluster. Our entities are "Persistent Data Objects" - so they hold persistent data but are also full objects in their own right, with methods and calculated (@Transient) data fields that I assume would not be propagated across a cluster? It's no hardship for us to forgo clustering anyway - we use sticky-sessions and can start a new session on a new node if the current one falls over.
I'm interested to read about the sharing of the contexts. This is very important - I can't see many scenarios where an app would only need to consume the EM from a single EJB. Our app is built around the (excellent) REST Easy framework. We use stateless beans to deliver the services and each bean accesses a single "Gateway" Stateful Session Bean (which controls the Extended Persistence Context) to access the object model. The REST services don't need to access the EntityManager themselves unless they want to remove or create an entity. In these scenarios, we found that we can inject an EntityManager into the StateLESS beans, and it is the same underlying object as the one in the StateFUL bean. (
Stateful.em.getDelegate() == Stateless.em.getDelegate()
This is very important - if unconnected EntityManagers were injected we would create havoc by adding entities to the object model!
It's interesting you say the persistence context is only supposed to be shared with other stateFUL beans. If that's the case:
* I'm not sure why our app works at all
* It might explain why we get some "detached entity" errors that we can't explain
* It means implementation of services would require stacks of stateful beans instead of stateless ones, which doesn't feel right.
I still can't understand why Extended Persistence Contexts haven't taken-off. They're a big leap towards allowing proper Java objects to be used in EJB, rather than pseudo-procedural routines organised in classes. (that comment might spur-on some extra posts... ).
One "how it works" question I would really love an answer to is: What happens to the Extended Persistence Context when an unhandled Exception erupts from the container? I'm not clear, because there are some conflicting signs:
* Hibernate docs say a session is invalidated (destroyed?) when an unhandled exception hits. This is requried to ensure consistency of the the Hibernate state.
* I think I saw the same about all StatefulSessionBeans in JBoss somewhere? (a stateful session bean is destroyed if an unhandled exception occurs?)
* I can specify @ApplicationException(rollback=false), which implies things can continue beyond the exception
* JTA lets me I can isolate transactions from each other and carry on (otherwise, a rollback at any point in a call-chain would destroy not-only the current calls but everything else attached to the Extended Context).#
* BUT: handling exceptions (like ContraintViolationException) at the "edge" of the container seems so obvious and usable with RESTEasy's exception handlers.
* We are seeing some session-closed errors (reported by HIbernate) in our tests and can't explain them. We aren't closing the session (and it's not timing out either) so can't figure out what's killing it.
I'd love to hear from some other users still, and to hear how they are using the Extended Persistence Contexts (and if not, why not). I'm happy to share more of our object interaction architecture as a discussion starter if it would help encourage people...
Regarding clustering, you certainly don't have to cluster your stateful session bean but its good to know that you could if you wanted to. If your extended persistence context has pending data changes, you might want the pending data changes to be replicated to other cluster nodes so that you could failover to another node. The pending data changes will be in your extended persistence context, when you persist entities without involving a JTA transaction (they stay pending until you invoke a stateful method that uses a transaction). This is often described as a long running conversation or shopping cart type bean. Your stateful bean and entities also need to be serializable as well. Just because you could do this, doesn't mean that you should. It depends on what your needs are.
Regarding the sharing of the persistence contexts. Yes, we should definitely write about the sharing of the persistence contexts and the current rules. It is said that a persistence context is associated with a JTA transaction and will be available (via persistence unit name) to other beans that are invoked as part of that same transaction (this is considered persistence context propagation at the JTA transaction level).
The other kind of sharing is only between stateful session beans that occurs when the stateful beans are created. During stateful bean creation, the extended persistence context can be inherited from other stateful beans on the current thread. I was referring specifically to how only stateful beans can share the extended persistence context via inheritance. They are also propagated into the JTA transaction where stateless beans can also use them via a transaction scoped entity manager.
Regarding unhandled exceptions, that should be rolling back the JTA transaction. the JPA 2.0 specification rules are as follows:
Section 3.3.2 Transaction Rollback
For both transaction-scoped and extended persistence contexts, transaction rollback causes all pre-existing managed instances and removed instances to become detached. The instances’ state will be the state of the instances at the point at which the transaction was rolled back. Transaction rollback typicallycauses the persistence context to be in an inconsistent state at the point of rollback. In particular, the state of version attributes and generated state (e.g., generated primary keys) may be inconsistent. Instances that were formerly managed by the persistence context (including new instances that were made persistent in that transaction) may therefore not be reusable in the same manner as other detached objects—for example, they may fail when passed to the merge operation.
 These are instances that were persistent in the database at the start of the transaction.
 It is unspecified as to whether instances that were not persistent in the database behave as new instances or detached instances
after rollback. This may be implementation-dependent.
For your unexplainable "session is closed" tests, try enabling trace logging for org.jboss.as.jpa, that should give you more context as to what is going on.
Interestingly, Mark has managed to nail down quite a specific "issue" with the use of EPCs on JBoss, possibly anywhere. (https://community.jboss.org/message/763217#763217). It would appear that, within a single transaction, calling any method on a session bean before the exception is thrown causes the entities in the EPC to become immediately detatched. What's interesting is that an exception thrown before any calls to a session bean has no impact. Is this because any EPCs enrolled in a transaction where an exception occurs automatically detatch all of their entities?
If this is expected behaviour it is quite a significant "gotcha" for people to be aware-of with Extended Persistence Contexts. If you generate an exception (even something as run-of-the-mill as a Validation exception like ConstraintViolationException (which happens all the time using server-side validation through Hibernate validator), you MUST do so before the sessionBean is accessed IN ANY WAY - otherwise your EPC effectively needs reloading (or merging).
Scott (or anyone!) can you confirm that this is the way it's supposed to work? If so, what part could/ does @ApplicationException play? Would marking a ConstraintViolationException with @ApplicationException mean that it no longer detaches the entities? (I've come up with this thought thanks to this blog: http://blog.dblevins.com/2010/07/applicationexception-is-evil-sort-of.html )
Hope this is useful to other potential EPCers - would be good to hear from some of you...
Hi James, I responded to the forum post that you mentioned here.
Is this because any EPCs enrolled in a transaction where an exception occurs automatically detatch all of their entities?
As mentioned in https://community.jboss.org/message/763922#763922, extended persistence contexts that are associated with an active JTA transaction, will detach their entities at the time of transaction rollback.
Thanks very much Scott. You have told me before that a JTA rollback causes the entities to be detached, sorry it didn't register with me properly.
Is my understanding correct then, that marking ContraintViolationException as an ApplicationException will prevent the rollback and so prevent the entities from being detatched? It will mean that the validation must come before any modifications to the object state (as they won't be rolled back), but at least allows me to call other methods on the Stateful bean first, without causing everything to detach.
Thanks again, this sort of thing is gold dust
Tested it and @ApplicationException works/ is the key. Exceptions marked-up with this don't cause a rollback and so don't cause the entities to become detatched. Need to use it judiciously, as obviously any modifications made to application state before the exception is thrown will not be rolled-back, but that's a trade-off that we can work with in order to keep our large object model live in memory (and attached!).
Thanks again Scott for patiently sharing your knowledge of JPA and EPC.
1 of 1 people found this helpful
I use CDI @Produces/@Disposes pair for a @ConversationScoped EntityManager injection (from a @PersistenceUnit EE-injection). I think I had extended persistence contexts at one point, can't recall why I switched, perhaps it was some trouble with manual flushmode.
Interesting Nicklas, thank you for admitting you have used EPCs!
Could you possibly expand on how you tie the EntityManager to @ConversationScoped (and how you control when it is disposed)? I haven't used CDI outside JBoss so haven't explored the benefits of @Produces and @Disposes - anything you could share in terms of the relative merits over an EPC would be gratefully received.
Well for a starters, the benefit of the CDI-managed PC is that it can be injected even into non-EJB:s. If the producer method is @ConversationScoped, it means that it's proxied and you are going to get the same EM injected within that same conversation. You don't have to control the lifecycle or disposal, when the conversation is ended (or timed out), the corresponding disposal method will automatically be called. You have to join the conversation yourself, though (well, can be done with annotations and interceptors, too). In the producer method you can set manual flush so the flushing isn't bound to the transaction.