9 Replies Latest reply on Sep 29, 2007 1:32 PM by Matt Drees

    Can I manually commit a Transaction?

    Jake C Newbie

      In my Seam app, I upload a file, create a record for it in the DB, persist() and flush() it, then move the file to a folder for processing.

      The problem is that sometimes my file processing application gets the file before the record is visible in the DB.

      There isn't anything else happening in the method after moving the file, but apparently, Seam isn't quite speedy enough on committing the Transaction.

      There is no @PostCommit event, and @PostPersist is still too early. What I'd like to do is just commit the Transaction, then move the file. However, entityManager.getTransaction() throws "java.lang.IllegalStateException: JTA EntityManager cannot access a transactions".

      How do I move my files after the Transaction is committed? All I can really think of is manually committing the Transaction, but that doesn't seem to be allowed. Is there a way to do it? I don't want ALL my Transactions to require manual commit, just this one instance. Do I need to create a second core:managed-persistence-context in components.xml that points to a different persistence-unit in persistence.xml?

      Or is there some other way of doing this? I've seen the @Asynchronous annotation. If I call a method annotated with this from within a Transaction, am I guaranteed that it won't be triggered until after the Transaction has committed?

        • 1. Re: Can I manually commit a Transaction?
          Dustin Norlander Apprentice

          Handling your own transaction in seam is a nasty business, but here's how to do it :)

          in components.xml :

          <core:init debug="true" jndi-pattern="@jndiPattern@"
           user-transaction-name="java:/UserTransaction" />
          



          to commit a transaction:
          UserTransaction tx = (UserTransaction) new InitialContext().lookup("java:comp/UserTransaction");
          entityManager.flush();
          if (tx.getStatus() == Status.STATUS_ACTIVE)
           tx.commit();
          



          You'll probably need to start another transaction in order to avoid seam throwing 'no transaction' exceptions when the request is finished.

          good luck,
          -Dustin

          • 2. Re: Can I manually commit a Transaction?
            Christian Bauer Master

            ?! In fact, it's super easy:



            Transaction.instance().commit();
            Transaction.instance().begin();




            • 3. Re: Can I manually commit a Transaction?
              Matt Drees Master

              There actually is something like a @PostCommit event. You would use something like this in your action method:

              Events.instance().raiseTransactionSuccessEvent("copyFile");
              


              with an @Observer("copyFile") to actually do the copy.

              • 4. Re: Can I manually commit a Transaction?
                Jake C Newbie

                I tried dustismo's code and it worked without having to start another Transactcion. I'd be VERY surprised if committing the Transaction actually closed it.

                I haven't tried Christian's code yet because Matt's idea is precisely what I was looking for! I don't have a problem doing manual commits if it is on a Transaction I started, but I really don't like messing with a container's Transaction.

                However, even after adding <core:transactionListener/> to my components.xml to get past the "org.jboss.seam.core.transactionListener is not installed" exception, my method still isn't getting called. I'm using the form of raiseTransactionSuccessEvent() that has parameters (a single parameter, in my case), but it isn't being called.

                 Events.instance().raiseTransactionSuccessEvent("filesUploaded", uploadedFiles);
                


                ... and in the same file I have ...

                @Observer("filesUploaded")
                 public void filesUploaded(Map<File,UploadDocument> uploadedFiles) {
                 log.info("filesUploaded entered");
                 ...
                 }
                

                ... but the log message never prints, and my files don't get moved, although the Document records get into the database without any manual commits.

                What am I missing?

                • 5. Re: Can I manually commit a Transaction?
                  Jake C Newbie

                  I also tried the version of raiseTransactionSuccessEvent() that doesn't have any following parameters, and that never gets called either.

                  log.info("raising fileUploaded");
                   Events.instance().raiseTransactionSuccessEvent("fileUploaded");


                  ... and in the same class ...

                  @Observer("fileUploaded")
                   public void fileUploaded() {
                   log.info("fileUploaded entered");
                   }


                  What else do I need to do besides adding <core:transactionListener/> to my components.xml to get this to work? I don't see anything else in the Booking demo (which has an example of this) that seems relevant.

                  I should add that the code is in a Stateful, Conversation scoped bean, if that matters.

                  • 6. Re: Can I manually commit a Transaction?
                    Matt Drees Master

                    Odd. Both of those look fine to me, though to be honest, I've only used raiseTransactionSuccessEvent() once. You may have to break out the debugger to figure out what's going on.

                    Good luck!

                    • 7. Re: Can I manually commit a Transaction?
                      Jake C Newbie

                      Doh! *blush*

                      It worked just fine once I declared the Observer method in the bean's Interface...

                      Thanks for the help!

                      • 8. Re: Can I manually commit a Transaction?
                        Pete Muir Master

                        Can someone file a JIRA issue requesting better docs for raiseTransactionSuccessEvent please? Thanks!