11 Replies Latest reply on Apr 24, 2013 6:45 AM by strenkor

    Can't inject entityManager into application component?

    robjellinghaus

      Why doesn't this work?

      @Startup
      @Scope(APPLICATION)
      @Name("replogApplication")
      public class ReplogApplication {
      ...
       @In(create=true)
       private transient EntityManager entityManager;
      
       @Create
       public void init ()
       {
       log.debug("Creating replogApplication");
      
       // for now, create one SiteSynchronizer per defined Site
       List<Site> sites = entityManager.createQuery("from Site").getResultList(); // line 37
      ...
       }
      

      I get this at startup time:
      [testng] java.lang.NullPointerException
       [testng] at com.robjsoftware.replog.ReplogApplication.init(ReplogApplication.java:37)
       [testng] at com.robjsoftware.replog.ReplogApplication$$EnhancerByCGLIB$$dfe7020b.CGLIB$init$0(<generated>)
       [testng] at com.robjsoftware.replog.ReplogApplication$$EnhancerByCGLIB$$dfe7020b$$FastClassByCGLIB$$52404ff7.invoke(<generated>)
       [testng] at net.sf.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:167)
       [testng] at org.jboss.seam.interceptors.JavaBeanInterceptor$1.proceed(JavaBeanInterceptor.java:80)

      Why isn't an entityManager being injected? Is it against the rules for an application-scoped component to have an injected EntityManager? Couldn't find that documented anywhere. If I missed it, where was it documented?

      Thanks for any clues,
      Rob

      (P.S. Hope you had a great vacation Gavin! ... if you're back yet! :-)

        • 1. Re: Can't inject entityManager into application component?
          robjellinghaus

          Hm. Well, I tried making it a @Stateful bean, and went through some rigmarole with needing to put the init() method in the local interface.

          But it still fails. I now get this (sorry for the big mangled stacktrace, this forum isn't kind to long code lines):

          [testng] WARN 25-08 00:41:39,828 (Log4JLogger.java:warn:104) -Stateful session beans was bound to the APPLICATION context - note that it is not safe to make concurrent calls to the bean: replogApplication
           [testng] INFO 25-08 00:41:39,828 (Log4JLogger.java:info:94) -Component: replogApplication, scope: APPLICATION, type: STATEFUL_SESSION_BEAN, class: com.robjsoftware.replog.ReplogApplication, JNDI: ReplogApplication/local
          ...
           [testng] DEBUG 25-08 00:41:43,860 (EJBContainer.java:initialiseInterceptors:718) -Initialising interceptors for ReplogApplication...
           [testng] DEBUG 25-08 00:41:43,860 (EJBContainer.java:initialiseInterceptors:720) -Default interceptors: null
           [testng] DEBUG 25-08 00:41:43,860 (EJBContainer.java:initialiseInterceptors:723) -Class interceptors: []
           [testng] DEBUG 25-08 00:41:43,860 (EJBContainer.java:initialiseInterceptors:739) -All applicable interceptor classes: []
           [testng] INFO 25-08 00:41:43,860 (MCKernelAbstraction.java:install:84) -installing bean: jboss.j2ee:jar=test,name=ReplogApplication,service=EJB3 with dependencies:
           [testng] DEBUG 25-08 00:41:43,985 (EJB3InterceptorsFactory.java:createPerJoinpoint:100) -Bound interceptors for joinpoint: public void com.robjsoftware.replog.ReplogApplication.init() - [Lorg.jboss.ejb3.interceptor.InterceptorInfo;@150b45a
           [testng] DEBUG 25-08 00:41:44,000 (UserTransactionImpl.java:<init>:56) -new UserTx: org.jboss.ejb3.tx.UserTransactionImpl@bb6255
           [testng] DEBUG 25-08 00:41:44,032 (EJB3InterceptorsFactory.java:createPerJoinpoint:100) -Bound interceptors for joinpoint: public void com.robjsoftware.replog.ReplogApplication.init() - [Lorg.jboss.ejb3.interceptor.InterceptorInfo;@b0ede6
           [testng] DEBUG 25-08 00:41:44,032 (JaccHelper.java:addPermissions:143) -ReplogApplication has no
           @SecurityDomain - skipping JACC configuration
           [testng] INFO 25-08 00:41:44,032 (EJBContainer.java:start:553) -STARTED EJB: com.robjsoftware.replog.ReplogApplication ejbName: ReplogApplication
           [testng] DEBUG 25-08 00:41:44,063 (Ejb3Deployment.java:registerEJBContainer:440) -Bound ejb3 container jboss.j2ee:service=EJB3,jar=test,name=ReplogApplication
           [testng] DEBUG 25-08 00:41:44,063 (Log4JLogger.java:debug:84) -instantiating Seam component: isUserInRole
           [testng] DEBUG 25-08 00:41:44,063 (Log4JLogger.java:debug:84) -instantiating Seam component: statelessContext
           [testng] DEBUG 25-08 00:41:44,063 (Log4JLogger.java:debug:84) -instantiating Seam component: replogApplication
           [testng] DEBUG 25-08 00:41:44,063 (Log4JLogger.java:debug:84) -JNDI InitialContext properties:{java.naming.factory.initial=org.jnp.interfaces.LocalOnlyContextFactory, java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces}
           [testng] DEBUG 25-08 00:41:44,094 (SecurityAssociation.java:<clinit>:143) -Using ThreadLocal: false
           [testng] DEBUG 25-08 00:41:44,125 (ExtendedPersistenceContextPropagationInterceptor.java:invoke:50) -++++ LongLivedSessionPropagationInterceptor
           [testng] DEBUG 25-08 00:41:44,125 (ReplogApplication.java:init:37) -Creating replogApplication
           [testng] javax.ejb.EJBException: java.lang.NullPointerException
           [testng] at org.jboss.ejb3.tx.Ejb3TxPolicy.handleExceptionInOurTx(Ejb3TxPolicy.java:69)
           [testng] at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:83)
           [testng] at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:197)
           [testng] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:98)
           [testng] at org.jboss.aspects.tx.TxPropagationInterceptor.invoke(TxPropagationInterceptor.java:76)
           [testng] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:98)
           [testng] at org.jboss.ejb3.stateful.StatefulInstanceInterceptor.invoke(StatefulInstanceInterceptor.java:81)
           [testng] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:98)
           [testng] at org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:78)
           [testng] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:98)
           [testng] at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:47)
           [testng] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:98)
           [testng] at org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:106)
           [testng] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:98)
           [testng] at org.jboss.ejb3.stateful.StatefulContainer.localInvoke(StatefulContainer.java:189)
           [testng] at org.jboss.ejb3.stateful.StatefulLocalProxy.invoke(StatefulLocalProxy.java:98)
           [testng] at $Proxy55.init(Unknown Source)
           [testng] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
           [testng] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
           [testng] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
           [testng] at java.lang.reflect.Method.invoke(Method.java:585)
           [testng] at org.jboss.seam.util.Reflections.invoke(Reflections.java:13)
           [testng] at org.jboss.seam.util.Reflections.invokeAndWrap(Reflections.java:32)
           [testng] at org.jboss.seam.Component.callComponentMethod(Component.java:1338)
           [testng] at org.jboss.seam.Component.callCreateMethod(Component.java:1326)
           [testng] at org.jboss.seam.Component.newInstance(Component.java:1316)
           [testng] at org.jboss.seam.Component.getInstance(Component.java:1267)
           [testng] at org.jboss.seam.Component.getInstance(Component.java:1257)
           [testng] at org.jboss.seam.contexts.Lifecycle.startup(Lifecycle.java:125)
           [testng] at org.jboss.seam.contexts.Lifecycle.endInitialization(Lifecycle.java:104)
           [testng] at org.jboss.seam.init.Initialization.init(Initialization.java:199)
           [testng] at org.jboss.seam.mock.SeamTest.init(SeamTest.java:321)
           [testng] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
           [testng] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
           [testng] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
           [testng] at java.lang.reflect.Method.invoke(Method.java:585)
           [testng] at org.testng.internal.MethodHelper.invokeMethod(MethodHelper.java:529)
           [testng] at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:311)
           [testng] at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:149)
           [testng] at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:77)
           [testng] at org.testng.TestRunner.privateRun(TestRunner.java:614)
           [testng] at org.testng.TestRunner.run(TestRunner.java:505)
           [testng] at org.testng.SuiteRunner.privateRun(SuiteRunner.java:221)
           [testng] at org.testng.SuiteRunner.run(SuiteRunner.java:147)
           [testng] at org.testng.TestNG.createAndRunSuiteRunners(TestNG.java:576)
           [testng] at org.testng.TestNG.runSuitesLocally(TestNG.java:539)
           [testng] at org.testng.TestNG.run(TestNG.java:316)
           [testng] at org.testng.TestNG.privateMain(TestNG.java:666)
           [testng] at org.testng.TestNG.main(TestNG.java:608)
           [testng] Caused by: java.lang.NullPointerException
           [testng] at com.robjsoftware.replog.ReplogApplication.init(ReplogApplication.java:40)
           [testng] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
           [testng] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
           [testng] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java
          :25)
           [testng] at java.lang.reflect.Method.invoke(Method.java:585)
           [testng] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:109)
           [testng] at org.jboss.ejb3.interceptor.InvocationContextImpl.proceed(InvocationContextImpl.java:166)
           [testng] at org.jboss.ejb3.interceptor.EJB3InterceptorsInterceptor.invoke(EJB3InterceptorsInterceptor.java:63)
           [testng] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:98)
           [testng] at org.jboss.ejb3.entity.ExtendedPersistenceContextPropagationInterceptor.invoke(ExtendedPersistenceContextPropagationInterceptor.java:57)
           [testng] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:98)
           [testng] at org.jboss.ejb3.entity.TransactionScopedEntityManagerInterceptor.invoke(TransactionScopedEntityManagerInterceptor.java:54)
           [testng] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:98)
           [testng] at org.jboss.ejb3.AllowedOperationsInterceptor.invoke(AllowedOperationsInterceptor.java:47)
           [testng] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:98)
           [testng] at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:79)
           [testng] ... 47 more

          You guessed it... same darn NullPointerException because entityManager is null.

          What am I missing? I have plain old POJOs in my session scope that I inject an EntityManager to in exactly the same way. Why is this not working at application scope?

          Maybe there's another way to do what I'm wanting to do here... basically, I want there to be some application component that maintains a list of "synchronizers", one synchronizer per Site entity that exists in the database. Perhaps I want a stateless component that extracts the list of sites, and then have the application component inject that SiteList and construct its synchronizers from that? I'll try that next (but not tonight, it's 1 AM ;-). But it'd still be nice to know the theory behind why what I'm doing here isn't supported... or know what I'm doing wrong!

          Thanks,
          Rob

          • 2. Re: Can't inject entityManager into application component?
            robjellinghaus

            Well well well. Some random forum surfing and one more try, and now this works:

            /**
             * Local interface to replog.
             * TODO: do we really want this??? are we getting into a synchronization mess?!?!?!?! or is it Just Right????????
             */
            @Local
            public interface Replog {
             public void init();
            
             public void destroy();
            
             public Site getSite();
            }
            
            @Startup
            @Scope(APPLICATION)
            @Stateful
            @Name("replogApplication")
            public class ReplogApplication implements Replog {
            ...
             @PersistenceContext // why does this work but @In doesn't?
             private transient EntityManager entityManager;
            
             // SiteSynchronizers, indexed by Site
             private Map synchronizers = new HashMap();
            
             /** The Site we consider to be "this application's site" */
             private Site site;
            
             @Create
             public void init ()
             {
             log.debug("Creating replogApplication");
            
             // for now, create one SiteSynchronizer per defined Site
             List<Site> sites = entityManager.createQuery("from Site").getResultList();
            
             for (Site site : sites) {
             synchronizers.put(site, new SiteSynchronizer(site));
            ...
             }
             }
            
             @Remove @Destroy
             public void destroy () {
             }
            
             /** Get the current Site. Should this really be an Application context component instead????? */
             public Site getSite () {
             return site;
             }
            }

            So, @PersistenceContext was part of the secret. Looks like the EJB3 lifecycle methods have to be in the local interface too. I would probably know this if I hadn't started learning Seam before EJB3....

            Why does @PersistenceContext work here but @In doesn't? I think I'm good to go now (modulo the possibility that I'm still arranging my components the wrong way, but some more code iteration will clue me in there). But I'm still curious why the first way didn't work; I think there's some deep Seam knowledge in there somewhere...?

            Cheers!
            Rob

            • 3. Re: Can't inject entityManager into application component?
              raja05

               

              "RobJellinghaus" wrote:

              Why does @PersistenceContext work here but @In doesn't? I think I'm good to go now (modulo the possibility that I'm still arranging my components the wrong way, but some more code iteration will clue me in there). But I'm still curious why the first way didn't work; I think there's some deep Seam knowledge in there somewhere...?


              Its because all of your @Ins and @Outs are Seam managed components and PersistenceContext is not. Its dependency injection by the EJB Container for the EntityManager object into your Beans. If you had a Seam Component that wraps the EntityManager, then you could use the @In there to get the variable but since thats not the case, your object wasnt getting initialized. Refer to
              http://java.sun.com/javaee/5/docs/api/javax/persistence/PersistenceContext.html

              • 4. Re: Can't inject entityManager into application component?
                robjellinghaus

                That's a nice stab at an explanation, but it can't be the whole story. Here's a session-scoped component that's been working just fine in my application for months now:

                @Name("replogSession")
                @Startup
                @Scope(SESSION)
                public class ReplogSession {
                ...
                 @In(create=true)
                 private transient EntityManager entityManager;
                
                 @In
                 private Replog replogApplication; // local interface of the stateful session bean above
                
                ...
                 public Changeset createChangeset (String description) {
                ...
                 Query query = entityManager.createQuery("from RepObject ro where ro.replicatedChangeset is null and " +
                 "not exists (from RepObject ro2 where ro2.replicatedChangeset is not null " +
                 "and ro2.version = ro.version and ro2.replicatedKey = ro.replicatedKey)");
                 List<RepObject> list = query.getResultList();
                ...
                }

                That's a plain old session-scoped POJO that has an EntityManager injected into it with @In. Works just great! I've never needed to use @PersistenceContext anywhere else in my app. And I have an EntityManager Seam component in my resources/WEB-INF/components.xml:
                <component name="entityManager" class="org.jboss.seam.core.ManagedPersistenceContext">
                <property name="persistenceUnitJndiName">java:/entityManagerFactory</property>
                </component>

                So why doesn't Seam's application scope support injecting that EntityManager with @In, when Seam's session scope does support it?

                Cheers!
                Rob

                • 5. Re: Can't inject entityManager into application component?
                  raja05

                  Ah okay, I dint know that you had the EntityManager defined in the components.xml. Ill give that a try(with this setup) and see what comes up.

                  • 6. Re: Can't inject entityManager into application component?
                    raja05

                    I just tried this -- with both the application and session scopes and they worked fine. I just modified the registration app that comes with the Seam distro to do this. Ill be interested to take a look at your app though.

                    Raja
                    rajasaur at gmail dot com

                    • 7. Re: Can't inject entityManager into application component?
                      bfo81

                      Maybe it's because of the phase. Injection by default only takes part when beginning the INVOKE_APPLICATION phase. I think the init() method gets called before the injection and so the EntityManager is null.

                      Try to annotate the bean with @Intercept(ALWAYS).

                      • 8. Re: Can't inject entityManager into application component?
                        gavin.king

                        Is this using current Seam CVS, or 1.0.1?

                        • 9. Re: Can't inject entityManager into application component?
                          robjellinghaus

                          This is with 1.0.1. Haven't tried @Intercept(ALWAYS) yet. Raja, what do you mean you modified the registration app to do this? That app, in 1.0.1, has no application-scoped components at all. What changes did you make and what components did you add?

                          • 10. Re: Can't inject entityManager into application component?
                            raja05

                            I modified the registration app not to work with EJBs but as Simple beans. The other changes are to make the REgisterAction bean as a Application scope bean and be available at Startup. I did those modifications just to make sure that your original problem description was happening for me too.

                            Here is a diff of what was changed ("registration" is the seam-example folder and "test" is my folder)

                            diff -r ../registration/src/org/jboss/seam/example/registration/RegisterAction.java src/org/jboss/seam/example/registration/RegisterAction.java
                            11a12,13
                            > import org.jboss.seam.annotations.Startup;
                            > import org.jboss.seam.ScopeType;
                            12a15
                            > import org.jboss.seam.annotations.Scope;
                            17d19
                            < @Stateless
                            18a21,22
                            > @Startup
                            > @Scope(ScopeType.APPLICATION)
                            25c29
                            < @PersistenceContext
                            ---
                            > @In(create=true)
                            32a37
                            > log.warn("EM: " + em);
                            diff -r ../registration/src/org/jboss/seam/example/registration/Register.java src/org/jboss/seam/example/registration/Register.java
                            6d5
                            < @Local
                            10c9
                            < }
                            \ No newline at end of file
                            ---
                            > }
                            


                            • 11. Re: Can't inject entityManager into application component?
                              strenkor

                              Thanks Rob,

                               

                              Your solution saved my day.

                               

                              I tried so many things with @Observer, @Asynchronous, @Transactional annotations and such, to no avail..