[
https://issues.apache.org/jira/browse/TOMEE-509?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13486785#comment-13486785
]
Donatas Ciuksys commented on TOMEE-509:
---------------------------------------
I'll try to explain why I'm so persistent :)
Imagine you'd like to implement some complicated/complex use-case that is of
conversation type (i.e. some wizard, checkout procedure, etc.). By
complicated/complex I mean that this use-case consist of 3-4 steps (imagine
wizard steps) and EACH of them requires entering much of data and/or complex
processing of that data and communication with DB. So approach to have one
component implementing the whole use-case is not correct from
OOAD/coupling/cohesion perspective. Programmer would be tended to have multiple
components, for example, one for each use-case step (or at least more than one
component). Now this is no longer documented obviously in EJB/JPA/CDI specs. I
see two ways to implement such a use-case:
1. "Propagated extended EntityManager" way - one Facade @ConversationScoped
Stateful EJB delegating business logic to other components.
a) Create Stateful @ConversationScoped EJB that governs the conversation (but
does not have business logic for separate steps). It declares
@PersistenceContext(EXTENDED) EntityManager em (though might not use it at all
itself). Lets call it Facade EJB.
Implement all the business logic methods within this Facade EJB that delegate
calls to other business logic components.
b) Create other business logic components (Stateless or @RequestScoped
Stateful, depending on business logic semantics). They declare
@PersistenceContext(TRANSACTIONAL), but always receive EntityManager from
Facade EJB by PersistenceContext propagation/inheritance
c) Create JSF page for each use-case step.
d) Apply strict limitations: all JSF pages are allowed to call ONLY Facade EJB
(otherwise EntityManager will not be propagated); Facade EJB calls business
logic components; business logic components do work and communicate with DB.
Such limitations ensure, that all business components during the whole
conversation are working with one and the same EntityManager instance (managed
by Facade EJB).
If somebody thinks that limitations above are too strict (programmer thinks: "I
want my JSF page to communicate with business logic component directly - I'm
tired to write hundreds of business logic delegate methods within Facade EJB;
CDI allows me to get rid of delegate methods, doesn't it???"):
2. "Injected extended EntityManager" way
a) Create Stateful @ConversationScoped EJB that governs the conversation (but
does not have business logic for separate steps). It declares
"@PersistenceContext(EXTENDED) EntityManager em" and has a producer that
returns this particular instance (NOT a new instance each time!!!) NO business
logic delegate methods.
b) Create other business logic components (Stateless or @RequestScoped
Stateful, depending on business logic semantics). They declare "@Inject
EntityManager em". In real-life we would create different qualifiers for
different conversations (use-cases) too (I would like future CDI to support
limited scope/namespace/module injection - not to inject anything from the
whole world)
c) Create JSF pages
d) Almost none limitations: As soon as one JSF page touches busines logic
component, it asks for injected EntityManager, Stateful @ConversationScoped
bean gets created, produces EntityManager, and so on... (of course,
conversation.begin() needs to be called, but this is not a problem).
No. 2 is better, because:
- no delegate methods are needed
- JSF pages call business components directly - less sophisticated code.
Up to now only Glassfish allows me to implement conversation use-case in 2.
way.
> Injected extended EntityManager is not registered (cannot be used for DB
> operations)
> ------------------------------------------------------------------------------------
>
> Key: TOMEE-509
> URL: https://issues.apache.org/jira/browse/TOMEE-509
> Project: TomEE
> Issue Type: Bug
> Affects Versions: 1.5.0, 1.5.1
> Environment: Windows 7 x64; jdk1.7.0_09 32 bit;
> apache-tomee-1.5.1-20121026.064316-51-webprofile.zip
> Reporter: Donatas Ciuksys
> Priority: Critical
>
> 1. Create class EntityManagerProducer:
> @SessionScoped
> @Stateful
> public class EntityManagerProducer implements Serializable {
>
> @PersistenceContext(type=PersistenceContextType.EXTENDED)
> private EntityManager em;
>
> @Produces
> public EntityManager getEntityManager() {
> return em;
> }
> }
> 2. Create injection client:
> @Named
> public class A {
>
> @Inject
> private EntityManager em;
> public String getDelegateClassName() {
> return em.getDelegate().getClass().getCanonicalName();
> }
>
> }
> 3. Create JSF page and try to call getDelegateClassName():
> <h:body>
> EntityManager is open: #{a.delegateClassName}
> </h:body>
> 4. Deploy (successful) and run the application - observe error message
> (printed in browser):
> An Error Occurred:
> InternalError: an entity manager should already be registered for this
> extended persistence unit
> viewId=/index.xhtml
> location=D:\dev\proj\templates\InjectionDemo\build\web\index.xhtml
> phaseId=RENDER_RESPONSE(6)
> Caused by:
> java.lang.IllegalStateException - InternalError: an entity manager should
> already be registered for this extended persistence unit
> at
> org.apache.openejb.persistence.JtaEntityManagerRegistry.getEntityManager(JtaEntityManagerRegistry.java:99)
> - Stack Trace
> java.lang.IllegalStateException: InternalError: an entity manager should
> already be registered for this extended persistence unit
> at
> org.apache.openejb.persistence.JtaEntityManagerRegistry.getEntityManager(JtaEntityManagerRegistry.java:99)
> at
> org.apache.openejb.persistence.JtaEntityManager.getEntityManager(JtaEntityManager.java:80)
> at
> org.apache.openejb.persistence.JtaEntityManager.getDelegate(JtaEntityManager.java:114)
> at
> org.apache.openejb.persistence.JtaEntityManager.getDelegate(JtaEntityManager.java:53)
> at beans.A.getDelegateClassName(A.java:19)
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> ...
--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira