Uploaded image for project: 'TomEE'
  1. TomEE
  2. TOMEE-509

Injected extended EntityManager is not registered (cannot be used for DB operations)

Details

    • Bug
    • Status: Resolved
    • Critical
    • Resolution: Not A Problem
    • 1.5.0, 1.5.1
    • None
    • None
    • None
    • Windows 7 x64; jdk1.7.0_09 32 bit; apache-tomee-1.5.1-20121026.064316-51-webprofile.zip

    Description

      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)
      ...

      Attachments

        Activity

          probably means the statful doesn't exist

          since the extended em only exist in the stateful context using it outside (in cdi) is not as obvious as it can seem

          romain.manni-bucau Romain Manni-Bucau added a comment - probably means the statful doesn't exist since the extended em only exist in the stateful context using it outside (in cdi) is not as obvious as it can seem

          This is not CDI related. Following example uses only EJB 3.1 functionality, yet still throws the same exception:

          ---------------------------------------
          @Stateful
          public class EntityManagerProducer implements Serializable {

          @PersistenceContext(type=PersistenceContextType.EXTENDED)
          private EntityManager em;

          public EntityManager getEntityManager()

          { return em; }

          }

          @Stateless
          public class A implements {

          @EJB
          private EntityManagerProducer entityManagerProducer;

          public String getDelegateClassName()

          { return entityManagerProducer.getEntityManager().getDelegate().getClass().getCanonicalName(); }

          }
          ---------------------------------------

          I checked both EJB and JPA specifications: there is no restriction to USE (not to create) Extended entityManager outside the stateful EJB. I understand that this is dangerous (yet very usefull implementing conversations), but this is not specification compliant. And by the way, this is working OK in Glassfish.

          Should I fill the bug for OpenEJB? For what version?

          donatasc Donatas Ciuksys added a comment - This is not CDI related. Following example uses only EJB 3.1 functionality, yet still throws the same exception: --------------------------------------- @Stateful public class EntityManagerProducer implements Serializable { @PersistenceContext(type=PersistenceContextType.EXTENDED) private EntityManager em; public EntityManager getEntityManager() { return em; } } @Stateless public class A implements { @EJB private EntityManagerProducer entityManagerProducer; public String getDelegateClassName() { return entityManagerProducer.getEntityManager().getDelegate().getClass().getCanonicalName(); } } --------------------------------------- I checked both EJB and JPA specifications: there is no restriction to USE (not to create) Extended entityManager outside the stateful EJB. I understand that this is dangerous (yet very usefull implementing conversations), but this is not specification compliant. And by the way, this is working OK in Glassfish. Should I fill the bug for OpenEJB? For what version?

          This worked for me on trunk

          BTW you shouldn't inject a stateful with @EJB, you should do a lookup to get it

          romain.manni-bucau Romain Manni-Bucau added a comment - This worked for me on trunk BTW you shouldn't inject a stateful with @EJB, you should do a lookup to get it

          side note about the original error: about your exception: such an entity manager (of a stateful) only exist if the stateful exist, if you produce the em (without scope??) the stateful hasn't to exist (and that's the case you had) so the real em doesn't exist too. That's why you got this error which is normal.

          Finally about "there is no restriction": in specification you should have a look to the opposite: "is it explicitely allowed". Not forbidden doesn't mean allowed (that's a pain but that's already better this way than without any spec ).

          romain.manni-bucau Romain Manni-Bucau added a comment - side note about the original error: about your exception: such an entity manager (of a stateful) only exist if the stateful exist, if you produce the em (without scope??) the stateful hasn't to exist (and that's the case you had) so the real em doesn't exist too. That's why you got this error which is normal. Finally about "there is no restriction": in specification you should have a look to the opposite: "is it explicitely allowed". Not forbidden doesn't mean allowed (that's a pain but that's already better this way than without any spec ).

          > BTW you shouldn't inject a stateful with @EJB, you should do a lookup to get it
          Yes, I know This was artificial to just create an example without CDI.

          I'll check with the most recent snapshot too.

          donatasc Donatas Ciuksys added a comment - > BTW you shouldn't inject a stateful with @EJB, you should do a lookup to get it Yes, I know This was artificial to just create an example without CDI. I'll check with the most recent snapshot too.

          > This worked for me on trunk
          Sorry, I trimmed the example too much (took some time for me to nail it down). This one is not working on todays snapshot version:

          @Named
          @Stateless
          public class A {

          private EntityManager em;

          @EJB
          private EntityManagerProducer entityManagerProducer;

          public String getDelegateClassName()

          { //return entityManagerProducer.getEntityManager().getDelegate().getClass().getCanonicalName(); // <-- WORKING OK return em.getDelegate().getClass().getCanonicalName(); // <-- NOT WORKING }

          @PostConstruct
          public void construct()

          { this.em = entityManagerProducer.getEntityManager(); }

          }

          @Stateful
          public class EntityManagerProducer implements Serializable {

          @PersistenceContext(type=PersistenceContextType.EXTENDED)
          private EntityManager em;

          public EntityManager getEntityManager()

          { return em; }

          }

          index.xhtml:

          <h:body>
          EntityManager delegate: #

          {a.delegateClassName}

          </h:body>

          donatasc Donatas Ciuksys added a comment - > This worked for me on trunk Sorry, I trimmed the example too much (took some time for me to nail it down). This one is not working on todays snapshot version: @Named @Stateless public class A { private EntityManager em; @EJB private EntityManagerProducer entityManagerProducer; public String getDelegateClassName() { //return entityManagerProducer.getEntityManager().getDelegate().getClass().getCanonicalName(); // <-- WORKING OK return em.getDelegate().getClass().getCanonicalName(); // <-- NOT WORKING } @PostConstruct public void construct() { this.em = entityManagerProducer.getEntityManager(); } } @Stateful public class EntityManagerProducer implements Serializable { @PersistenceContext(type=PersistenceContextType.EXTENDED) private EntityManager em; public EntityManager getEntityManager() { return em; } } index.xhtml: <h:body> EntityManager delegate: # {a.delegateClassName} </h:body>

          > such an entity manager (of a stateful) only exist if the stateful exist, if you produce the em (without scope??) the stateful hasn't to exist (and that's the case you had) so the real em doesn't exist too

          Nope, real process is different, as per CDI spec:

          5.5.4. Invocation of producer or disposer methods
          When the container calls a producer or disposer method, the behavior depends upon whether the method is static or nonstatic:
          • If the method is static, the container must invoke the method.
          • Otherwise, if the method is non-static, the container must:

          • Obtain a contextual instance of the bean which declares the method, as defined by Section 6.5.2, “Contextual instance
            of a bean”.
          • Invoke the method upon this instance, as a business method invocation, as defined in Section 7.2, “Container invocations
            and interception”.

          So, stateful EJB is being constructed before producer method invocation (and put to respective CDI context for further reuse).

          donatasc Donatas Ciuksys added a comment - > such an entity manager (of a stateful) only exist if the stateful exist, if you produce the em (without scope??) the stateful hasn't to exist (and that's the case you had) so the real em doesn't exist too Nope, real process is different, as per CDI spec: 5.5.4. Invocation of producer or disposer methods When the container calls a producer or disposer method, the behavior depends upon whether the method is static or nonstatic: • If the method is static, the container must invoke the method. • Otherwise, if the method is non-static, the container must: Obtain a contextual instance of the bean which declares the method, as defined by Section 6.5.2, “Contextual instance of a bean”. Invoke the method upon this instance, as a business method invocation, as defined in Section 7.2, “Container invocations and interception”. So, stateful EJB is being constructed before producer method invocation (and put to respective CDI context for further reuse).

          which annotation on A.em? (doesn't appear in JIRA comment, not sure that's a copy/paste error or a jira front issue)

          romain.manni-bucau Romain Manni-Bucau added a comment - which annotation on A.em? (doesn't appear in JIRA comment, not sure that's a copy/paste error or a jira front issue)

          > which annotation on A.em?
          None This is just temporary variable (could be made transient too).

          donatasc Donatas Ciuksys added a comment - > which annotation on A.em? None This is just temporary variable (could be made transient too).

          well your example still sounds weird to me since if you imagine you have multiple instance of your em holder you can't know which em reference you expect when calling em in your code (well i understood what you expected but the spec speaks about extended em inheritance which is not always what you expect)

          so for me it is still not so clear

          wdyt?

          romain.manni-bucau Romain Manni-Bucau added a comment - well your example still sounds weird to me since if you imagine you have multiple instance of your em holder you can't know which em reference you expect when calling em in your code (well i understood what you expected but the spec speaks about extended em inheritance which is not always what you expect) so for me it is still not so clear wdyt?

          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.

          donatasc Donatas Ciuksys added a comment - 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.

          Did you try using a stateful as entry point?

          romain.manni-bucau Romain Manni-Bucau added a comment - Did you try using a stateful as entry point?

          > Did you try using a stateful as entry point?
          That would be option No. 1 (above) - Yes, it seems to work OK with Tomee.

          donatasc Donatas Ciuksys added a comment - > Did you try using a stateful as entry point? That would be option No. 1 (above) - Yes, it seems to work OK with Tomee.

          can match 1 or 1bis : stateful can hold business code. What i meant is stateful are not evil and can be used as any other bean. This way you avoid the side effects you can get with 2

          romain.manni-bucau Romain Manni-Bucau added a comment - can match 1 or 1bis : stateful can hold business code. What i meant is stateful are not evil and can be used as any other bean. This way you avoid the side effects you can get with 2

          I'm not sure I got your idea. I'm not against stateful beans - option 1 is using stateful beans for business logic (Facade statul ejb call/delegates to business stateful ejbs).

          My point was that single stateful ejb sometimes is not enough - you want to implement complex use-case with several OO classes. Question is how to bind them together.

          donatasc Donatas Ciuksys added a comment - I'm not sure I got your idea. I'm not against stateful beans - option 1 is using stateful beans for business logic (Facade statul ejb call/delegates to business stateful ejbs). My point was that single stateful ejb sometimes is not enough - you want to implement complex use-case with several OO classes. Question is how to bind them together.

          Personally i let a stateful matching a wizard but depend on your architecture too

          romain.manni-bucau Romain Manni-Bucau added a comment - Personally i let a stateful matching a wizard but depend on your architecture too

          FYI: similar GlassFish issue was fixed:
          http://java.net/jira/browse/GLASSFISH-11805

          donatasc Donatas Ciuksys added a comment - FYI: similar GlassFish issue was fixed: http://java.net/jira/browse/GLASSFISH-11805
          donatasc Donatas Ciuksys added a comment - I have asked EJB experts for their opinion: http://java.net/projects/ejb-spec/lists/users/archive/2012-11/message/0

          Ok great,

          FYI you should be able to produce the em now even with session scope (but it will still fail later because the stateful was not touched)

          romain.manni-bucau Romain Manni-Bucau added a comment - Ok great, FYI you should be able to produce the em now even with session scope (but it will still fail later because the stateful was not touched)

          Actually it would be really enough if this would work with @ConversationScoped @Stateful. As was noted by Mark, nobody want @SessionScoped EntityManager (and it makes no sense).

          Thanks, I'll try it out with the next snapshot.

          donatasc Donatas Ciuksys added a comment - Actually it would be really enough if this would work with @ConversationScoped @Stateful. As was noted by Mark, nobody want @SessionScoped EntityManager (and it makes no sense). Thanks, I'll try it out with the next snapshot.

          right replace session by passivable scope in my previous sentence

          romain.manni-bucau Romain Manni-Bucau added a comment - right replace session by passivable scope in my previous sentence

          Tomee snapshot building process seems to be down, the last snapshot is of october-29.

          donatasc Donatas Ciuksys added a comment - Tomee snapshot building process seems to be down, the last snapshot is of october-29.

          any news?

          romain.manni-bucau Romain Manni-Bucau added a comment - any news?

          EJB experts did not answer to my question. I've posted the question to JPA 2.1 spec users mailing list:

          http://java.net/projects/jpa-spec/lists/users/archive/2013-01/message/51

          donatasc Donatas Ciuksys added a comment - EJB experts did not answer to my question. I've posted the question to JPA 2.1 spec users mailing list: http://java.net/projects/jpa-spec/lists/users/archive/2013-01/message/51

          I've create a JPA JIRA issue "Explicitly allow or disallow use of Entity Manager with extended Persistence Context for CDI injection":
          http://java.net/jira/browse/JPA_SPEC-46

          ldemichiel responded: I think this is probably more an EJB issue than a JPA one, but in any case it is something that we should evaluate for the next release.

          Lets close this with "Invalid" or something similar.

          donatasc Donatas Ciuksys added a comment - I've create a JPA JIRA issue "Explicitly allow or disallow use of Entity Manager with extended Persistence Context for CDI injection": http://java.net/jira/browse/JPA_SPEC-46 ldemichiel responded: I think this is probably more an EJB issue than a JPA one, but in any case it is something that we should evaluate for the next release. Lets close this with "Invalid" or something similar.

          People

            Unassigned Unassigned
            donatasc Donatas Ciuksys
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: