9 Replies Latest reply on Aug 31, 2007 8:02 AM by Troy Tarrrant

    How to get EntityManager without @In?

    Troy Tarrrant Newbie

      Hi,

      I have a private thread running inside an application scoped component that wakes up every 5 secs and does some housekeeping work. It needs access to an EntityManager.

      The @In is unreliable the em is always null. So I tried this:

      EntityManagerFactory emf = Persistence.createEntityManagerFactory("viewDatabase");
      EntityManager em = emf.createEntityManager();
      


      but when I tried to use it nothing happened, I figured it wasn't being flushed automatically as I know seam does a lot for you but when I manually tried to flush() it I got complaints about not being in a transaction.

      I then tried to get a transaction from em.getTransaction() but then I got:

      java.lang.IllegalStateException: JTA EntityManager cannot access a transactions
      


      Makes sense from the reading of done on EJB just now, so then I thought I'll try getting from JNDI as the reading I've done says the persistence context will be associated with a transaction.

      How does one do this? Is this indeed the right thinking (or indeed the right forum for this or shall I post it in the EJB forum or JBoss forum?) Please advise.

      Thanks

      Troy

        • 1. Re: How to get EntityManager without @In?
          Alex Ka Novice

          Try Component.getInstance("entityManager", true)

          • 2. Re: How to get EntityManager without @In?
            Troy Tarrrant Newbie

            Good idea, I tried it but got

            21:11:46,928 ERROR [STDERR] Exception in thread "Thread-21"
            21:11:46,928 ERROR [STDERR] java.lang.IllegalStateException: No application context active
            21:11:46,928 ERROR [STDERR] at org.jboss.seam.Component.forName(Component.java:1690)
            21:11:46,928 ERROR [STDERR] at org.jboss.seam.Component.getInstance(Component.java:1740)
            21:11:46,928 ERROR [STDERR] at org.jboss.seam.Component.getInstance(Component.java:1723)
            21:11:46,928 ERROR [STDERR] at model.EXAccessPoint.flushToDb(EXAccessPoint.java:217)
            21:11:46,928 ERROR [STDERR] at model.EXAccessPoint.access$0(EXAccessPoint.java:207)
            21:11:46,928 ERROR [STDERR] at model.EXAccessPoint$InvalidateList.run(EXAccessPoint.java:257)


            Then I noticed that my em has ended up in the conversation scope

            21:10:18,545 INFO [Component] Component: em, scope: CONVERSATION, type: JAVA_BEAN, class: org.jboss.seam.persistence.ManagedPersistenceContext
            


            My components.xml looks like

            <core:init debug="true" jndi-pattern="isis-prototype/#{ejbName}/local" transaction-management-enabled="true" />
            
            
             <security:identity authenticate-method="#{authenticator.authenticate}"/>
            
             <web:multipart-filter create-temp-files="true"
             max-request-size="1000000"
             url-pattern="*.seam"/>
            
             <web:context-filter url-pattern="/content/*"/>
            
             <persistence:managed-persistence-context name="em" auto-create="true"
             persistence-unit-jndi-name="java:/viewEntityManagerFactory"/>


            and my persistence.xml looks like

             <persistence-unit name="viewDatabase">
             <provider>org.hibernate.ejb.HibernatePersistence</provider>
             <jta-data-source>java:/viewDatasource</jta-data-source>
             <properties>
             <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
             <property name="hibernate.show_sql" value="false"/>
             <!-- These are the default for JBoss EJB3, but not for HEM: -->
             <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider"/>
             <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
             <property name="jboss.entity.manager.factory.jndi.name" value="java:/viewEntityManagerFactory"/>
             </properties>
             </persistence-unit>


            Any ideas?

            I can't remember how I did this, but I did read the seam manual on transactions in conversations and (in another class unrelated to this) I followed the approach given, which was to set the flush mode to manual to get the atomic transactions across a conversation on a @Begin, so...

            @Scope(ScopeType.CONVERSATION)
            public class MaintainProfileAction implements Serializable {
            ...
             @Begin(join=true, flushMode=FlushModeType.MANUAL)
             public void find() {
            ...
            


            has this forever put the em in conversation scope I wonder ?

            Any ideas? another persistence unit?

            Troy

            • 3. Re: How to get EntityManager without @In?
              Pete Muir Master

              An SMPC is in the conversation scope always as the ManagedPersistenceContext component is annotated @Scope(CONVERSATION).

              Anyway, look at ContextualHttpServletRequest for how to set up and tear down the context.

              • 4. Re: How to get EntityManager without @In?
                Natalia Ponomareva Newbie

                Why don't u use EJB3 timers? You can create timer that will do ur "housekeeping" work, and it will survive redeploys and server shutdown. Besides, in this case EM will be accessible automatically.
                try something like this

                @Stateless
                @Name("jobsTimer")
                public class JobsTimerIMPL implements JobsTimer {
                 @Resource
                 javax.ejb.TimerService timerService;
                
                 @In
                 EntityManager entityManager;
                
                 @Logger
                 private Log log;
                
                 public void createTimer() {
                 Timer timer = timerService.createTimer(5, 5, "timer that fires every 5 sec and starts 5 sec after it was created");
                 }
                
                 @Timeout
                 public void timeout(Timer timer) {
                 //em must be automatically accessable here
                 log.info(em);
                 }
                

                So create timer with createTimer method, and then timeout method wll be called every 5 sec

                • 5. Re: How to get EntityManager without @In?
                  Troy Tarrrant Newbie

                  I thought about using timers but got discouraged when in the spec it says


                  While timer durations are express in millisecond units, this is because the millisecond is the unit of time granularity used by the API...it is expected that most timed events will correspond to hours, days or longer...


                  and then later on it says


                  The timer service is intended for the modeling of long lived business processes.


                  So I came to the conclusion that it was a bit of an overkill and hence thought a simple background thread should do it.

                  I tried Pete's idea of trying to setup the contexts for the thread, but the problem there lies in the fact that I can't because the ThreadLocal storages access is local to the seam package so I can't actually set anything on it :(

                  If all else fails, I guess I'll have to use timers.

                  • 6. Re: How to get EntityManager without @In?
                    Pete Muir Master

                    Use Seam managed timers. 1) Simple timers (default, don't persist across application restart), 2) EJB3 (do persist - but this can be not the beehaviour you want), 3) Quartz (don't persist, good business interval support)

                    • 7. Re: How to get EntityManager without @In?
                      Natalia Ponomareva Newbie

                      May be this can work

                      Lifecycle.beginCall();
                      Component.getInstance("entityManager", true)
                      Lifecycle.endCall();

                      I used that in MDB to get some seam components...

                      • 8. Re: How to get EntityManager without @In?
                        Troy Tarrrant Newbie

                        Thanks for the suggestions, I tried the beginCall() ... endCall() on the lifecycle and yes that does work, I can get an EntityManager in my thread however back to the original problem, the entity manager has not started a transaction for me, so nothing gets posted to the db and when I flush I get

                        23:15:43,708 ERROR [STDERR] Exception in thread "Thread-21"
                        23:15:43,708 ERROR [STDERR] javax.persistence.TransactionRequiredException: no transaction is in progress
                        23:15:43,708 ERROR [STDERR] at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:293)
                        23:15:43,708 ERROR [STDERR] at org.jboss.seam.persistence.EntityManagerProxy.flush(EntityManagerProxy.java:90)
                        23:15:43,708 ERROR [STDERR] at model.EXAccessPoint.flushToDb(EXAccessPoint.java:236)
                        23:15:43,708 ERROR [STDERR] at model.EXBackgroundThread.run(EXBackgroundThread.java:36)
                        23:15:44,282 INFO [EXAccessPoint] calculateEx():from=11:15:39 PM;now=11:15:44 PM;exs.size()=3;currentStartIndex=2
                        


                        The code inside the thread does this at the moment

                        Lifecycle.beginCall();
                        EntityManager em = (EntityManager)Component.getInstance("em", true);
                        ...
                        em.persist(...);
                        ...
                        em.flush();
                        Lifecycle.endCall();
                        


                        I'll try JNDI directly...

                        • 9. Re: How to get EntityManager without @In?
                          Troy Tarrrant Newbie

                          Thanks guys for all your help, I learnt a lot on this thread.

                          In the end I just wrote a SLSB using a @PersistenceContext annotation to get my EntityManager then I just did a lookup via JNDI in the housekeeping thread to get it then called a write method on it passing the object requiring the housekeeping.

                          Thanks

                          Troy