4 Replies Latest reply on Jul 18, 2007 9:48 AM by Roberto Melo Cavalcante

    Problem with Threads and Transactional context

    Roberto Melo Cavalcante Newbie

      Hi guys!

      I've done the same post on Seam's, because I thought that would be a good place to put the question together with others posts with similar problem. As it is indeed an EJB3 related problem, I make the same post here too. So please don't be mad with me because this problem is taking away my sleep and may cost my job.

      Here is the post:
      ---------------------
      I'm using threads inside a stateless bean and I cannot persist anything without having that annoying message that states I can only use transaction manager inside a transactional context.
      I've tried to make a busy-wait on my stateless bean so I can assure my bean will be alive until the very moment my thread needs the entityManager but when the execution reaches the entityManeger.merge( object ) an exception is risen.
      The story:

      I have a jboss-4.0.5.GA with an upgrade on my original Javassist. Now I have javassist-3.4 due to issues with threads.
      My application needs to perform a fork in execution flow split in three parts. Both of them are created as threads and are observed in normal-fashion-way observer pattern, where the Stateless Bean is the observer.
      I have a hunch that my bean life-cycle ends before my first thread finishes, so the entityManager looses it transactional context.
      Can anybody point a blueprint for creating a structure to support such a business demand?

      Here some parts of my code so you can place yourself. This code comes with only one thread. The original one has three, all like this one.

      @TransactionManagement(TransactionManagementType.CONTAINER)
      public @Stateless(name = "TempoRealRN") class TempoRealRNBean extends IntegratorCommonBehavior implements TempoRealRN, Observer {

      @EJB(beanName = "GenericoDAO")
      GenericoDAO genericoDAO;

      @PersistenceContext private EntityManager entityManager;

      private static final Log log = LogFactory.getLog(TempoRealRNBean.class);

      ...
      public void processar(CommonController controladorComum) throws IntegratorException {

      super.setEntityManager(this.entityManager);

      tCorFrente = new ThreadCorFrente(controladorComum, this, log, dto, nomeThreadFrente, grupoFrente);
      tCorFrente.addObserver(this);
      tCorFrente.start();
      }// ends of: public void processar(...) ....

      /*
      * receives notification from thread state change and executes the proper action to acomplish bussiness rule goals.
      *
      */
      public void update(Object o) {

      //perform some state tests

      //then try to persist.
      //at this point an exception is risen
      this.entityManager.merge( object );

      }//ends public void update(Object o)

      }//ends class

      The exception risen is:
      --------------------------
      17:01:47,480 ERROR [STDERR] Caused by: javax.persistence.TransactionRequiredException: EntityManager must be access within a transaction
      17:01:47,480 ERROR [STDERR] at org.jboss.ejb3.entity.ManagedEntityManagerFactory.verifyInTx(ManagedEntityManagerFactory.java:150)
      17:01:47,480 ERROR [STDERR] at org.jboss.ejb3.entity.TransactionScopedEntityManager.merge(TransactionScopedEntityManager.java:180)
      17:01:47,480 ERROR [STDERR] at wm.integrator.negocio.temporeal.impl.TempoRealRNBean.persistirFrente(TempoRealRNBean.java:485)

      It would be great if some good soul could enlight me regarding on how to use the proper pattern for observing threads and how I can make this persistence work.
      Thank you all just for being patient enough to read this extensive post.
      I apologize myself for any English grammar misuse or misspell as English is not my 1st language. I'm from Brazil.

        • 1. Re: Problem with Threads and Transactional context
          wayne baylor Apprentice

          My guess is that the problem stems from your thread trying to invoke EntityManager.merge(). Since your thread probably doesn't do any transaction management you are getting that TransactionRequiredException.

          Before you try to fix that though, consider that you probably shouldn't be spawning your own threads inside the app server. I would try to find a different way that doesn't involve spawning any threads.

          • 2. Re: Problem with Threads and Transactional context
            Roberto Melo Cavalcante Newbie

            Dear waynebaylor,

            Ty very much for your answer. Although, I'm not trying to persist anything inside my threads. What I'm doing inside my threads in to use the genericDAOBean to perform some searchs.
            About the thread spawning, can you or anyone suggest a better way to do it?

            Ty again.

            Roberto Cavalcante

            • 3. Re: Problem with Threads and Transactional context
              Bill Burke Master

              You can pass this pointers around of EJBs and expect transactions to work. This is because EJBs have a container that sits in front of bean instances so that it can handle things like transaction bounders.

              You should instead do:

              @Resource SessionContext ctx;
              
              
              public void processar(...)
              {
               TempoRealRN thisPtr = ctx.getBusinessInterface(TempoRealFN.class);
               CorFrente = new ThreadCorFrente(controladorComum, this, log, dto, nomeThreadFrente, grupoFrente);
               tCorFrente.addObserver(this);
               tCorFrente.start();
              }
              
              


              You'll also have to have TempoRealFN extend the Observer interface probably.

              • 4. Re: Problem with Threads and Transactional context
                Roberto Melo Cavalcante Newbie

                Thank you very much Bill.

                I'll try it right away!

                But first Let me see if I understood you right. I'll keep my Stateless Bean,but I'll add this SessionContext to keep the bean alive when the threads stop running so I can use the Stateless Bean entityManager or I should use SessionContext to make the persistence somehow?
                You please excuse my newbie questions.
                If I do have to use the SessionContext for persistence, could you, please, tell me how?

                Ty very much again and God blesses you and your family.