2 Replies Latest reply on Jun 21, 2010 4:56 PM by Shawn Zimmerman

    EJB is already associated with an incomplete transaction

    Shawn Zimmerman Newbie

      I am receiving the following error message.  I am using Seam 2.2.0, Glassfish v2 and Hibernate.


      [#|2010-06-18T18:02:30.277-0400|INFO|sun-appserver2.1|javax.enterprise.system.container.ejb|_ThreadID=20;_ThreadName=httpSSLWorkerThread-8080-0;|
      javax.ejb.EJBException: nested exception is: java.lang.IllegalStateException: EJB is already associated with an incomplete transaction
      java.lang.IllegalStateException: EJB is already associated with an incomplete transaction
           at com.sun.ejb.containers.BaseContainer.useClientTx(BaseContainer.java:3501)
           at com.sun.ejb.containers.BaseContainer.preInvokeTx(BaseContainer.java:3323)
           at com.sun.ejb.containers.BaseContainer.preInvoke(BaseContainer.java:1253)
           at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:195)
           at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:127)
           at $Proxy319.isAwareOfContainerTransactions(Unknown Source)
           at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
           at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
           at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
           at java.lang.reflect.Method.invoke(Method.java:597)
           at org.jboss.seam.util.Reflections.invoke(Reflections.java:22)
           at org.jboss.seam.intercept.RootInvocationContext.proceed(RootInvocationContext.java:32)
           at org.jboss.seam.intercept.ClientSideInterceptor$1.proceed(ClientSideInterceptor.java:76)
           at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:107)
           at org.jboss.seam.intercept.ClientSideInterceptor.invoke(ClientSideInterceptor.java:54)
           at org.javassist.tmp.java.lang.Object_$$_javassist_seam_1.isAwareOfContainerTransactions(Object_$$_javassist_seam_1.java)
           at org.jboss.seam.transaction.CMTTransaction.registerSynchronization(CMTTransaction.java:116)
           at org.jboss.seam.persistence.ManagedPersistenceContext.joinTransaction(ManagedPersistenceContext.java:125)
           at org.jboss.seam.persistence.ManagedPersistenceContext.getEntityManager(ManagedPersistenceContext.java:111)




      Here is the code.


      @Stateful
      @Name("userList")
      @Scope(SESSION)
      @Restrict("#{identity.loggedIn}")
      @TransactionAttribute(REQUIRES_NEW)
      public class UserListAction implements UserList, Serializable {
           private static final long serialVersionUID = -6838835156002279984L;
      
           @PersistenceContext
           private EntityManager entityManager;
      
           @In
           private IdentityManager identityManager;
      
           @DataModel
           private List<UserAccount> userAccounts;
           @DataModelSelection
           private UserAccount userAccount;
      
           @In
           private FacesMessages facesMessages;
           
           @Logger
           private Log log;
      
           @Factory
           @Observer("userConfirmed")
           public void getUserAccounts() {
                log.info("Pulling new users from persistence.");
                userAccounts = entityManager.createQuery("SELECT u FROM UserAccount u")
                          .getResultList();
           }
      
           public UserAccount getUserAccount() {
                return userAccount;
           }
      
           public void disableUser() {
                log.info("Disabling user #0", userAccount.getUsername());
      
                new RunAsOperation() {
                     public void execute() {
                          identityManager.disableUser(userAccount.getUsername());
                          
                          // TODO: Shouldn't need to do this!
                          //userAccount.setEnabled(false);
                          //entityManager.merge(userAccount);
                     }
                }.addRole("admin").run();
                
                getUserAccounts();
      
                facesMessages.add("User disabled for user #0",
                          userAccount.getUsername());
           }
      
           public void enableUser() {
                log.info("Enabling user #0", userAccount.getUsername());
      
                new RunAsOperation() {
                     public void execute() {
                          identityManager.enableUser(userAccount.getUsername());
                          
                          // TODO: Shouldn't need to do this!
                          //userAccount.setEnabled(true);
                          //entityManager.merge(userAccount);
                     }
                }.addRole("admin").run();
      
                getUserAccounts();
      
                facesMessages.add("User enabled for user #0",
                          userAccount.getUsername());
           }
      
           public void deleteUser() {
                log.info("Deleting user #0", userAccount.getUsername());
      
                // TODO: RunAs only for testing purposes!
                new RunAsOperation() {
                     public void execute() {
                          identityManager.deleteUser(userAccount.getUsername());
                     }
                }.addRole("admin").run();
      
                getUserAccounts();
      
                facesMessages.add("User deleted for user #0",
                          userAccount.getUsername());
           }
      
           @Remove
           public void destroy() {
           }
      }



      I am able to get it working using the Entity Manager though I should be able to do this using the Identity Manager.  What could I be doing wrong?


      identityManager.disableUser(userAccount.getUsername());
                          
      // TODO: Shouldn't need to do this!
      //userAccount.setEnabled(false);
      //entityManager.merge(userAccount);



      Any direction would be appreciated!






        • 1. Re: EJB is already associated with an incomplete transaction
          Thomas Jonsson Newbie

          What happens if you not inject the entityManager?

          • 2. Re: EJB is already associated with an incomplete transaction
            Shawn Zimmerman Newbie

            I revised the code and took out the entityManager by using only the itentityManager functions.  It worked!  Then I slowly added in the entityManager again to identity the issue and it continued to work...  I don't know what is different.  One item I modified was to add identity.addRole("admin") so I didn't need to RunAsOperation().


            The new issue I have is the #{identityManager.isUserEnabled(userAccount.username)} and #{userAccount.enabled} initialize with correct values from the database but as soon as I enable/disable, the {#userAccount.enabled} is always the inverted value (true/false and false/true from what is in the DB).


            I wonder if the entityManager query is pulling from a cache hit not knowing identityManager has modified it.  Any ideas??


            New UserListAction:


            @Stateful
            @Name("userList")
            @Scope(SESSION)
            @Restrict("#{identity.loggedIn}")
            @TransactionAttribute(REQUIRES_NEW)
            public class UserListAction implements UserList, Serializable {
                 private static final long serialVersionUID = -6838835156002279984L;
            
                 @PersistenceContext
                 private EntityManager entityManager;
            
                 @In
                 private IdentityManager identityManager;
            
                 @DataModel
                 private List<UserAccount> userAccounts;
                 @DataModelSelection
                 private UserAccount userAccount;
            
                 @In
                 private FacesMessages facesMessages;
            
                 @Logger
                 private Log log;
            
                 @Factory
                 @Observer("userConfirmed")
                 public void getUserAccounts() {
                      Query query = entityManager.createQuery("SELECT a FROM UserAccount a");
                      userAccounts = query.getResultList();
            
                      //users = identityManager.listUsers();
                 }
            
                 public UserAccount getUserAccount() {
                      return userAccount;
                 }
            
                 public void disableUser() {
                      identityManager.disableUser(userAccount.getUsername());
                      //entityManager.flush();
                      getUserAccounts();
            
                      facesMessages.add("User disabled for #0", userAccount.getUsername());
                 }
            
                 public void enableUser() {
                      identityManager.enableUser(userAccount.getUsername());
                      //entityManager.flush();
                      getUserAccounts();
            
                      facesMessages.add("User enabled for #0", userAccount.getUsername());
                 }
            
                 @Remove
                 public void destroy() {
                 }
            }



            Here is my xhtml:


              <h:form id="users">
                 <h:outputText id="NoUsersFoundMessage" value="No Users Found" rendered="#{userAccounts.rowCount==0}"/>
                 <h:dataTable id="userAccounts" value="#{userAccounts}" var="userAccount" rendered="#{userAccounts.rowCount>0}">
                      <h:column id="column1">
                           <f:facet id="NameFacet" name="header">Username</f:facet>
                           #{userAccount.username}
                      </h:column>
                      <h:column id="column2">
                           <f:facet id="LastNameFacet" name="header">Last Name</f:facet>
                           #{userAccount.user.lastName}
                      </h:column>
                      <h:column id="column3">
                           <f:facet id="FirstNameFacet" name="header">First Name</f:facet>
                           #{userAccount.user.firstName}
                      </h:column>
                      <h:column id="column4">
                           <f:facet id="EnabledFacet" name="header">Enabled (Persistence)</f:facet>
                           #{userAccount.enabled}
                      </h:column>
                      <h:column id="column5">
                           <f:facet id="EnabledFacet" name="header">Enabled (IdentityManager)</f:facet>
                           #{identityManager.isUserEnabled(userAccount.username)}
                      </h:column>
                      <h:column id="column6">
                           <f:facet id="ActionFacet" name="header">Actions</f:facet>
                                <h:commandLink id="disable" value="Disable" action="#{userList.disableUser}"
                                     rendered="#{identityManager.isUserEnabled(userAccount.username)}" /> 
                            <h:commandLink id="enable" value="Enable" action="#{userList.enableUser}"
                                 rendered="#{!identityManager.isUserEnabled(userAccount.username)}" />
                      </h:column>
                 </h:dataTable>
              </h:form>