0 Replies Latest reply on Mar 17, 2008 10:47 AM by Sylvain Leroux

    jPDL pageflow persistence and exceptions

    Sylvain Leroux Newbie

      Hi everybody!


      I'm having hard-time to handle exceptions when using jPDL pageflow.


      In two words, I try to handle the Duplicate entry case (javax.persistence.EntityExistsException) when persisting an entity in a conversation whose navigation is using jPDL pageflow.


      My pageflow


      So, I have a task that allow a user to create a two different (but related) entities in a row.


      Here's the pageflow (human readable - mostly): page 1 is the form, page 2 is the confirmation page. A that point, the user may either go back to the form, or confirm, then the entity is persisted, and the pageflow continues, with similar steps to create the second entity.


      And here's the pageflow (human readable - more or less):


      <pageflow-definition xmlns="http://jboss.com/products/seam/pageflow"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://jboss.com/products/seam/pageflow http://jboss.com/products/seam/pageflow-2.0.xsd"
           name="creation_moule">
      
      
           <start-state>
                <transition to="Formulaire creation moule" />
           </start-state>
      
           <page name="Formulaire creation moule"
                view-id="/choix_action/creation_moule/newmoule.xhtml">
                <redirect />
                <transition to="Confirmation création moule" name="valider"></transition>
           </page>
           <page name="Confirmation création moule"
                view-id="/choix_action/creation_moule/recapitule.xhtml">
                <redirect />
                <transition to="Formulaire creation pièce" name="confirmer">
                     <action expression="#{creation_moule.essayerEnregistrerMoule()}" />
                     <action expression="#{creation_piece.test()}"/>
                     <action
                          expression="#{creation_piece.commenceAvecMoule(creation_moule.moule)}" />
                </transition>
                <transition name="modifier" to="Formulaire creation moule"></transition>
           </page>
           <page name="Formulaire creation pièce"
                view-id="/choix_action/creation_piece/newpiece.xhtml">
                <redirect />
                <transition to="Confirmation création pièce" name="valider"></transition>
           </page>
           <page name="Confirmation création pièce"
                view-id="/choix_action/creation_piece/recapitule.xhtml">
                <transition to="Formulaire creation pièce" name="modifier"></transition>
                <transition name="confirmer" to="Menu principal">
                     <action expression="#{creation_piece.enregistrerPiece()}" />
                </transition>
           </page>
           <page name="Menu principal" view-id="/choix_action/choix.xhtml">
                <end-conversation />
                <redirect />
           </page>
      </pageflow-definition>
      



      The key point is at transition <transition to="Formulaire creation pièce" name="confirmer">. Here, I have two actions: The first one to persist the entity creation_moule.moule. The second to start the second entity creation (creation_piece).


      The problem


      Here's my problem: entities created by this pageflow have fields that should be unique. In fact, the primary key is a value entered by the user:


      @Entity
      public class Moule {
          @Id
          public String numMoule;
      
          private String typeInjection;
          private long maintenance;
          private int nombreEmpreinte;
      
      ...
      



      Of course, the problem is when a user attempt to create a moule with a reference (moule.numMoule) already in the database.


      I tried to handle that in my session bean, by explicitly flushing the transaction and catching the corresponding exception:


      @Stateful
      @Scope(CONVERSATION)
      @Name("creation_moule")
      public class CreationMoule implements CreationMoulePubli {
          @Logger Log          logger;
          
          @PersistenceContext(type = EXTENDED)
          private EntityManager em;
      
          private Moule moule;
      
      ...
          
          @Override
          public void essayerEnregistrerMoule() {
           logger.error("begin");
           try {
                logger.error("begin try");
                em.persist(moule);
                em.flush();
                logger.error("end try");
      //         enregistrerMoule();
               //return true;
           }
           catch(Exception e) {
                logger.error("begin catch");
      //         em.clear();
               moule = new Moule("numMoule", "typeInjection", 123, 45);
               logger.error("catched generic Exception " + e.toString());
                logger.error("end catch");
               //return false;
           }
           logger.error("end");
      
          }
      ...
      



      As you could see by extensive use of the poor's man debugging tools like logger.error and by commenting out code, it doesn't work as I wish: when I run the app, if there's already an entity with the user supplied id (numMoule), I got:


      09:18:19,318 ERROR [CreationMoule] begin
      09:18:19,318 ERROR [CreationMoule] begin try
      09:18:19,320 INFO  [STDOUT] Hibernate: insert into Moule (typeInjection, maintenance, nombreEmpreinte, numMoule) values (?, ?, ?, ?)
      09:18:19,330 WARN  [JDBCExceptionReporter] SQL Error: 1062, SQLState: 23000
      09:18:19,330 ERROR [JDBCExceptionReporter] Duplicate entry 'numMoule' for key 1
      09:18:19,330 ERROR [AbstractFlushingEventListener] Could not synchronize database state with session
      org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
              at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
              at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
              at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253)
              at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:237)
              at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:141)
              at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
              at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
              at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
              at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:296)
              at org.jboss.ejb3.entity.ExtendedEntityManager.flush(ExtendedEntityManager.java:121)
              at org.jboss.seam.persistence.EntityManagerProxy.flush(EntityManagerProxy.java:90)
              at com.glory.action.CreationMoule.essayerEnregistrerMoule(CreationMoule.java:43)
              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.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:112)
              at org.jboss.ejb3.interceptor.InvocationContextImpl.proceed(InvocationContextImpl.java:166)
              at org.jboss.seam.intercept.EJBInvocationContext.proceed(EJBInvocationContext.java:44)        at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:56)
              at org.jboss.seam.persistence.ManagedEntityIdentityInterceptor.aroundInvoke(ManagedEntityIdentityInterceptor.java:48)
              at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
              at org.jboss.seam.transaction.RollbackInterceptor.aroundInvoke(RollbackInterceptor.java:31)
              at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
              at org.jboss.seam.bpm.BusinessProcessInterceptor.aroundInvoke(BusinessProcessInterceptor.java:49)
              at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
              at org.jboss.seam.core.MethodContextInterceptor.aroundInvoke(MethodContextInterceptor.java:42)
              at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
              at org.jboss.seam.persistence.EntityManagerProxyInterceptor.aroundInvoke(EntityManagerProxyInterceptor.java:26)
              at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
              at org.jboss.seam.persistence.HibernateSessionProxyInterceptor.aroundInvoke(HibernateSessionProxyInterceptor.java:27)
              at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
              at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:106)
              at org.jboss.seam.intercept.SessionBeanInterceptor.aroundInvoke(SessionBeanInterceptor.java:50)
              at sun.reflect.GeneratedMethodAccessor506.invoke(Unknown Source)
              at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
              at java.lang.reflect.Method.invoke(Method.java:597)
              at org.jboss.ejb3.interceptor.InvocationContextImpl.proceed(InvocationContextImpl.java:118)
              at org.jboss.ejb3.interceptor.EJB3InterceptorsInterceptor.invoke(EJB3InterceptorsInterceptor.java:63)
              at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
              at org.jboss.ejb3.entity.ExtendedPersistenceContextPropagationInterceptor.invoke(ExtendedPersistenceContextPropagationInterceptor.java:71)
              at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
              at org.jboss.ejb3.entity.TransactionScopedEntityManagerInterceptor.invoke(TransactionScopedEntityManagerInterceptor.java:54)
              at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
              at org.jboss.ejb3.AllowedOperationsInterceptor.invoke(AllowedOperationsInterceptor.java:47)
              at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
              at org.jboss.aspects.tx.TxPolicy.invokeInCallerTx(TxPolicy.java:126)
              at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:195)
              at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
              at org.jboss.aspects.tx.TxPropagationInterceptor.invoke(TxPropagationInterceptor.java:76)
              at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
              at org.jboss.ejb3.stateful.StatefulInstanceInterceptor.invoke(StatefulInstanceInterceptor.java:83)
              at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
              at org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:77)
              at org.jboss.ejb3.security.Ejb3AuthenticationInterceptor.invoke(Ejb3AuthenticationInterceptor.java:106)
              at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
              at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:46)
              at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
              at org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:106)
              at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
              at org.jboss.ejb3.stateful.StatefulContainer.localInvoke(StatefulContainer.java:204)
              at org.jboss.ejb3.stateful.StatefulLocalProxy.invoke(StatefulLocalProxy.java:100)
              at $Proxy369.essayerEnregistrerMoule(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:21)
              at org.jboss.seam.intercept.RootInvocationContext.proceed(RootInvocationContext.java:31)
              at org.jboss.seam.intercept.ClientSideInterceptor$1.proceed(ClientSideInterceptor.java:76)
              at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:56)
              at org.jboss.seam.ejb.RemoveInterceptor.aroundInvoke(RemoveInterceptor.java:41)
              at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
              at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:106)
              at org.jboss.seam.intercept.ClientSideInterceptor.invoke(ClientSideInterceptor.java:54)
              at org.javassist.tmp.java.lang.Object_$$_javassist_2.essayerEnregistrerMoule(Object_$$_javassist_2.java)
      
      <snip>
      
              ... 141 more
      09:18:19,355 ERROR [CreationMoule] begin catch
      09:18:19,355 ERROR [CreationMoule] catched generic Exception javax.persistence.EntityExistsException: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
      09:18:19,356 ERROR [CreationMoule] end catch
      09:18:19,356 ERROR [CreationMoule] end
      09:18:19,378 ERROR [GraphElement] action threw exception: couldn't evaluate expression '#{creation_piece.test()}'
      org.jbpm.JbpmException: couldn't evaluate expression '#{creation_piece.test()}'
              at org.jbpm.jpdl.el.impl.JbpmExpressionEvaluator.evaluate(JbpmExpressionEvaluator.java:43)
              at org.jbpm.jpdl.el.impl.JbpmExpressionEvaluator.evaluate(JbpmExpressionEvaluator.java:30)
              at org.jbpm.graph.def.Action.execute(Action.java:118)
              at org.jboss.seam.bpm.SeamUserCodeInterceptor.executeAction(SeamUserCodeInterceptor.java:70)
              at org.jbpm.graph.def.GraphElement.executeAction(GraphElement.java:253)
              at org.jbpm.graph.def.GraphElement.executeActions(GraphElement.java:220)
              at org.jbpm.graph.def.GraphElement.fireAndPropagateEvent(GraphElement.java:190)
              at org.jbpm.graph.def.GraphElement.fireEvent(GraphElement.java:174)
              at org.jbpm.graph.def.Transition.take(Transition.java:138)
              at org.jbpm.graph.def.Node.leave(Node.java:393)
              at org.jbpm.graph.exe.Token.signal(Token.java:194)
              at org.jbpm.graph.exe.Token.signal(Token.java:157)
              at org.jbpm.graph.exe.ProcessInstance.signal(ProcessInstance.java:282)
              at org.jboss.seam.pageflow.Pageflow.signal(Pageflow.java:477)
              at org.jboss.seam.pageflow.Pageflow.navigate(Pageflow.java:336)
              at org.jboss.seam.jsf.SeamNavigationHandler.handleNavigation(SeamNavigationHandler.java:40)
              at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:119)
              at javax.faces.component.UICommand.broadcast(UICommand.java:383)
              at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:447)
              at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:752)
              at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:97)
              at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:251)
              at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:117)
              at javax.faces.webapp.FacesServlet.service(FacesServlet.java:244)
              at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
              at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
              at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
              at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:58)
              at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
              at org.jboss.seam.debug.hot.HotDeployFilter.doFilter(HotDeployFilter.java:68)
              at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
              at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:85)
              at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
              at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)
              at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
              at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:44)
              at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
              at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)
              at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
              at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
              at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
              at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
              at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
              at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)        at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:179)
              at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
              at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
              at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
              at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
              at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
              at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:241)
              at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
              at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:580)
              at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
              at java.lang.Thread.run(Thread.java:619)
      Caused by: javax.el.ELException: javax.ejb.EJBTransactionRolledbackException: No active JTA transaction on joinTransaction call
              at org.jboss.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:332)
              at org.jboss.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:273)
              at org.jboss.el.parser.AstMethodSuffix.getValue(AstMethodSuffix.java:59)
              at org.jboss.el.parser.AstValue.getValue(AstValue.java:67)
              at org.jboss.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:186)
              at org.jboss.seam.bpm.SeamExpressionEvaluator$1.evaluate(SeamExpressionEvaluator.java:77)
              at org.jboss.seam.bpm.SeamExpressionEvaluator.evaluate(SeamExpressionEvaluator.java:36)
              at org.jbpm.jpdl.el.impl.JbpmExpressionEvaluator.evaluate(JbpmExpressionEvaluator.java:39)
              ... 55 more
      Caused by: javax.ejb.EJBTransactionRolledbackException: No active JTA transaction on joinTransaction call
              at org.jboss.ejb3.tx.Ejb3TxPolicy.handleInCallerTx(Ejb3TxPolicy.java:87)
              at org.jboss.aspects.tx.TxPolicy.invokeInCallerTx(TxPolicy.java:130)
              at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:195)
              at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
              at org.jboss.aspects.tx.TxPropagationInterceptor.invoke(TxPropagationInterceptor.java:76)
              at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
              at org.jboss.ejb3.stateful.StatefulInstanceInterceptor.invoke(StatefulInstanceInterceptor.java:83)
              at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
              at org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:77)
              at org.jboss.ejb3.security.Ejb3AuthenticationInterceptor.invoke(Ejb3AuthenticationInterceptor.java:106)
              at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
              at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:46)
              at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
              at org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:106)
              at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
              at org.jboss.ejb3.stateful.StatefulContainer.localInvoke(StatefulContainer.java:204)
              at org.jboss.ejb3.stateful.StatefulLocalProxy.invoke(StatefulLocalProxy.java:100)
              at $Proxy370.test(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:21)
              at org.jboss.seam.intercept.RootInvocationContext.proceed(RootInvocationContext.java:31)
              at org.jboss.seam.intercept.ClientSideInterceptor$1.proceed(ClientSideInterceptor.java:76)
       
      <snip>
      



      This leads to one question - and one problem:



      • I could see my catch block is entered, by what's this 09:18:19,330 ERROR [AbstractFlushingEventListener] Could not synchronize database state with session
        org.hibernate.exception.ConstraintViolationException
        ? Is this only a log, or the exception has fired something behind me?

      • Why the second action could not be executed ([GraphElement] action threw exception: couldn't evaluate expression '#{creation_piece.test()}'
        org.jbpm.JbpmException: couldn't evaluate expression '#{creation_piece.test()}'
        )? Since I have catched the exception, it should be transparent to jBPM? Or is it related to the part of the trace like javax.ejb.EJBTransactionRolledbackException: No active JTA transaction on joinTransaction call?



      By writing this, I suspect there's a problem with the current transaction being marked for rollback when the conflict is detected at em.flush time, and no longer being usable by jBPM and/or my second session bean (creation_piece).


      So how to handle the Duplicate entry case? Is the pattern try{ em.persist(...); em.flush(); } catch(...) {} the right thing to do? Or there is a better way to handle that?


      Hope you could help me,

      Sylvain.