8 Replies Latest reply on Jun 9, 2009 6:34 AM by gonorrhea

    Modeling LRCs and java.IllegalStateException

    gonorrhea

      Seam 2.0.2-FP


      Scenario: 1 JSF/facelet, 2 SFSB, two forms, one form embedded in modalPanel


      I have a LRC started with one SFSB.  Client initiates a promotion attempt to LRC via action method call in the 2nd SFSB (@Begin, not @Begin(join=true))


      I get this exception:


      Caused by: java.lang.IllegalStateException: begin method invoked from a long-running conversation, try using @Begin(join=true) on method: populateListValueParam



      I actually need a new LRC started b/c the SMPC is scoped to conversation (not SFSB life like container-managed extended or SFSB transaction like container-managed tx-scoped) and when the em.flush() occurs and tx commits, changes to both forms persist as updates to db.  I want changes to one form at a time, per submit action, to occur.  This behavior is basically a bug.


      I am trying to achieve atomic conversations with Hibernate MANUAL flush and SMPC for both SFSBs/LRCs.


      I'm not sure it's possible to achieve this using nested conversations and not update the data in the other form/table (keep updates isolated).


      I tried using the following but my dataTable does not render and I'm not sure you can use Hibernate MANUAL flush with container-managed extended PC anyways:


      @PersistenceContext(unitName="boBETS", type=PersistenceContextType.EXTENDED)
      private EntityManager entityManager;



      btw, the reason I actually need two LRCs simultaneously is because the 2nd backing bean is for a form embedded in a modalPanel in same xhtml. 


      Any ideas for solving this scenario?  I'm trying to use the write-behind feature of JPA/Hibernate to issue the update statement when I call em.flush() rather than keeping track of which values in which rows of the dataTable have changed and which entities to merge(), etc.

        • 1. Re: Modeling LRCs and java.IllegalStateException
          gonorrhea

          btw, both forms have multiple rows with multiple cells/fields that can be modified by the user.


          that's why I'd like to take advantage of write-behind and auto dirty checking features of PC and em.flush() in the @End methods.


          From SiA:



          Maintain a persistence context —The persistence context is an in-memory cache of
          all entity instances that have been loaded into memory by this manager. It is the
          key to optimizing performance and enabling write-behind database operations
          (queued SQL statements). It’s often referred to as the “first-level” cache. The terms
          persistence context and persistence manager are often used interchangeably.



          Perform automatic dirty checking —The state of managed objects that reside in the
          persistence context are monitored throughout the lifetime of the persistence
          context. When the persistence manager is flushed, the pending changes in the
          entity instances are sent to the database as a batch of SQL statements. Once an
          object becomes detached, changes to it are no longer monitored.
          • 2. Re: Modeling LRCs and java.IllegalStateException
            gonorrhea

            In Seam 2.x, can you start more than one simultaneous LRC in the same browser tab/JSF page?  If yes, how?  If not, why not?

            • 3. Re: Modeling LRCs and java.IllegalStateException
              gonorrhea

              Ok so I just tried the following in both SFSBs:


              @PersistenceContext(unitName="boBETS", type=PersistenceContextType.EXTENDED)
              private EntityManager entityManager;



              One SFSB is LRC, the other is temporary.


              I'm wondering if the PC is propagating somehow from one SFSB to the other.


              I entered a value in one cell in one form and another value in one cell in the other form (modalPanel) and clicked submit btn (code below) for the modalPanel form.


              Hibernate issued two update statements.


              @Stateful
              @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
              @Name("listValueParam")
              public class ListValueParamAction implements ListValueParamLocal {
              
                   @PersistenceContext(unitName="boBETS", type=PersistenceContextType.EXTENDED)
                   //@In
                   private EntityManager entityManager;
                   
                   @Logger
                   private Log log;
                   
                   @DataModel
                   private java.util.List<ListValueParam> populateListValueParamList;
                   
                   @In("listValueList")
                   private ListDataModel listValueListDataModel;
                   
                   @SuppressWarnings("unchecked")     
                   //Caused by: java.lang.IllegalStateException: begin method invoked from a long-running conversation, try using @Begin(join=true) on method: populateListValueParam
                   //@Begin(nested=true, flushMode=FlushModeType.MANUAL)
                   public void populateListValueParam(Integer rowIndex){
                        java.util.List<ListValue> listValueList = (java.util.List<ListValue>)listValueListDataModel.getWrappedData();
                        populateListValueParamList = entityManager.createQuery("select lvp from ListValueParam lvp where lvp.listValue.listValueId = :listValueId")
                                                                                    .setParameter("listValueId", listValueList.get(rowIndex).getListValueId())
                                                                                    .getResultList();
                   }
                        
                   //@End
                   @TransactionAttribute(TransactionAttributeType.REQUIRED)
                   public void saveListValueParamChanges(){
                        //entityManager.flush();
                        //AUTO flush!
                        entityManager.clear();
                        for (ListValueParam lvp : populateListValueParamList) {
                             entityManager.merge(lvp);
                        }          
                   }
                   
                   @Remove
                   public void destroy() {}
              
              }

              • 4. Re: Modeling LRCs and java.IllegalStateException
                gonorrhea

                void      clear()
                          Clear the persistence context, causing all managed entities to become detached.



                So when I call entityManager.clear() is the extended PC for this SFSB and the extended PC for the other SFSB being cleared or just this one?


                I'm absolutely and totally confused and frustrated, and I love the fact that the Seam core devs never respond on this forum anymore.  Fantastic.

                • 5. Re: Modeling LRCs and java.IllegalStateException
                  gonorrhea

                  just learned that you must use SMPC (@In EntityManager) with s:convertEntity.  That was the root cause as to why the dataTable was not rendering when I used @PersistenceContext to inject EntityManager.


                  I added a PU in persistence-dev.xml as follows (BETS2 is the new one):


                  <persistence-unit name="boBETS">
                        <provider>org.hibernate.ejb.HibernatePersistence</provider>
                        <jta-data-source>java:/boBETSDatasource</jta-data-source>
                        <properties>
                           <property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
                           <!-- <property name="hibernate.hbm2ddl.auto" value="validate"/>   -->
                           <property name="hibernate.show_sql" value="true"/>
                           <property name="hibernate.format_sql" value="true"/>
                           <property name="hibernate.generate_statistics" value="true"/>
                           <property name="jboss.entity.manager.factory.jndi.name" value="java:/boBETSEntityManagerFactory"/>
                           <property name="hibernate.default_catalog" value="boBETS"/>
                           <property name="hibernate.default_schema" value="dbo"/>
                        </properties>
                     </persistence-unit>
                     
                     <persistence-unit name="boBETS2">
                        <provider>org.hibernate.ejb.HibernatePersistence</provider>
                        <jta-data-source>java:/boBETSDatasource</jta-data-source>
                        <properties>
                           <property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
                           <!-- <property name="hibernate.hbm2ddl.auto" value="validate"/>   -->
                           <property name="hibernate.show_sql" value="true"/>
                           <property name="hibernate.format_sql" value="true"/>
                           <property name="hibernate.generate_statistics" value="true"/>
                           <property name="jboss.entity.manager.factory.jndi.name" value="java:/boBETSEntityManagerFactory"/>
                           <property name="hibernate.default_catalog" value="boBETS"/>
                           <property name="hibernate.default_schema" value="dbo"/>
                        </properties>
                     </persistence-unit>



                  I am using the boBETS in the 1st SFSB and the boBETS2 in the 2nd SFSB as follows:


                  @PersistenceContext(unitName="boBETS2", type=PersistenceContextType.EXTENDED)
                  private EntityManager entityManager;



                  I thought that would isolate the PC's but apparently not.  When the AUTO flush occurs in the 2nd SFSB method (with REQUIRED txtype), two updates are issued by hibernate.


                  I am going to try to modify the UI design such that the submit button in the modalPanel's form is removed and there is only one submit button for both forms (i.e. entire use case has one submit button).  That was I can use SMPC w/ hibernate manual flush to implement atomic conversation.


                  If somebody knows how to get this to work properly without removing one submit button, plz reply.  thx.

                  • 6. Re: Modeling LRCs and java.IllegalStateException
                    gonorrhea

                    Arbi Sookazian wrote on Jun 05, 2009 21:53:


                    I am going to try to modify the UI design such that the submit button in the modalPanel's form is removed and there is only one submit button for both forms (i.e. entire use case has one submit button).  That was I can use SMPC w/ hibernate manual flush to implement atomic conversation.

                    If somebody knows how to get this to work properly without removing one submit button, plz reply.  thx.


                    This solution works except in the case when user modifies data in form in modalPanel, closes modalPanel, then modifies data in JSF main page form, then clicks submit in main page form (but didn't want to save changes in modalPanel form).


                    I was thinking to add a reset button in modalPanel form.  There is a refresh() method in EntityManager API but you have to pass the entity instance for each one that needs to be refreshed.  And that means db hit for each call to that method.


                    There should be a way to reset (undo the dirty changes) in the PC.  Does JPA or Hibernate offer this method/service?  In Powerbuilder, the datawindow had three buffers and one of those was the original buffer.  I wonder if JPA/Hibernate has this useful buffer concept?


                    Primary
                    Data that has not been deleted or filtered out (that is, the rows that are viewable).


                    Filter
                    Data that was filtered out.


                    Delete
                    Data that was deleted by the user or through code.



                    • 7. Re: Modeling LRCs and java.IllegalStateException
                      gonorrhea

                      Ok, I finally implemented a solution for my problem (1 base updateable form plus additional modalPanel forms in the same JSF/xhtml page).


                      The POC solution involves the following components:


                      1 JSF/xhtml
                      2 SFSBs (one for base form and one for modalPanel form)


                      The solution in brief is as follows:


                      1) add an additional PU in persistence.xml with a unique jboss.entity.manager.factory.jndi.name value.  This PU is very similar to the original PU.


                      <persistence-unit name="boBETS">
                            <provider>org.hibernate.ejb.HibernatePersistence</provider>
                            <jta-data-source>java:/boBETSDatasource</jta-data-source>
                            <properties>
                               <property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
                               <!-- <property name="hibernate.hbm2ddl.auto" value="validate"/>   -->
                               <property name="hibernate.show_sql" value="true"/>
                               <property name="hibernate.format_sql" value="true"/>
                               <property name="hibernate.generate_statistics" value="true"/>
                               <property name="jboss.entity.manager.factory.jndi.name" value="java:/boBETSEntityManagerFactory"/>
                               <property name="hibernate.default_catalog" value="boBETS"/>
                               <property name="hibernate.default_schema" value="dbo"/>
                            </properties>
                         </persistence-unit>
                         
                         <!-- using boBETS2 for ListValueParamAction for now! trying to isolate the em.flush() such that we can achieve atomic conversations for the
                         base form as well as the popup form! -->    
                         
                         <persistence-unit name="boBETS2">
                            <provider>org.hibernate.ejb.HibernatePersistence</provider>
                            <jta-data-source>java:/boBETSDatasource</jta-data-source>
                            <properties>
                               <property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
                               <!-- <property name="hibernate.hbm2ddl.auto" value="validate"/>   -->
                               <property name="hibernate.show_sql" value="true"/>
                               <property name="hibernate.format_sql" value="true"/>
                               <property name="hibernate.generate_statistics" value="true"/>
                               <property name="jboss.entity.manager.factory.jndi.name" value="java:/boBETS2EntityManagerFactory"/>
                               <property name="hibernate.default_catalog" value="boBETS"/>
                               <property name="hibernate.default_schema" value="dbo"/>
                            </properties>
                         </persistence-unit>



                      2) add a config in components.xml for another SMPC very similar to the original SMPC config.


                      <persistence:managed-persistence-context name="entityManager"
                                                           auto-create="true"
                                            persistence-unit-jndi-name="java:/boBETSEntityManagerFactory"/>    
                         
                         <!-- using entityManager2 for ListValueParamAction for now! trying to isolate the em.flush() such that we can achieve atomic conversations for the
                         base form as well as the popup form! -->                   
                         <persistence:managed-persistence-context name="entityManager2"
                                                           auto-create="true"
                                            persistence-unit-jndi-name="java:/boBETS2EntityManagerFactory"/>  



                      3) in SFSB 1 inject entityManager


                      @In private EntityManager entityManager;



                      4) in SFSB 2 inject entityManager2


                      @In private EntityManager entityManager2;



                      So we flush() entityManager in one SFSB and flush() entityManager2() in the other (I'm not even sure if I should use @End or not in the SFSBs b/c I am using @Begin(join=true).  Seam will not allow me to start a new LRC (promotion) from an existing LRC.


                      This strategy isolates the conversations (persistence basically as there is only one LRC) and achieves isolated atomicity such that one flush() does not cause update/insert to the other forms when I submit the form in the modalPanels.


                      The problem is that in my use case, there is one base form in the xhtml and three modalPanels with insert/update forms.


                      So my question now is, from a best practices perspective, is it ok to use four different SMPCs with four PUs in the same app???

                      • 8. Re: Modeling LRCs and java.IllegalStateException
                        gonorrhea

                        Ok. So I realized that I only need 2 SMPCs and 2 PUs for one app for this particular scenario.  1 for the main form and 1 for any of the modalPanel forms in the same xhtml (i.e. same LRC).  I did a POC and it worked.