5 Replies Latest reply on Sep 19, 2007 10:22 AM by Alex Ka

    Recovering from a Constraint violation exception

    Alex Ka Novice

      Hi,
      I have an application using Seam 2.0.0.B1. A colleague was complaining that he cannot recover from a ConstraintViolationException. On a certain string field in the database there is a unique constraint. When the user tries to enter an existing value the database checks the constraint and an exception is fired. I believe this causes a rollback and closes the current transaction. After that it is impossible to work with the database. We have tried to request a new transaction so that we can reload the data that causes problems but we always receive errors about the transaction not being active:

      Caused by: java.sql.BatchUpdateException: ORA-00001: unique constraint (EXAM_CENTER.UK_EXAM_VENDOR_NAME) violated
      WARN [JDBCExceptionReporter] SQL Error: 1, SQLState: 23000
      17:29:34,562 ERROR [JDBCExceptionReporter] ORA-00001: unique constraint (EXAM_CENTER.UK_EXAM_VENDOR_NAME) violated
      17:29:34,562 ERROR [AbstractFlushingEventListener] Could not synchronize database state with session
      
      ...
      
      javax.faces.el.EvaluationException: javax.ejb.EJBTransactionRolledbackException: org.hibernate.exception.GenericJDBCException: Cannot open connection
       at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:91)
       at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:91)
      
      ...
      
      Caused by: org.jboss.util.NestedSQLException: Transaction is not active: tx=TransactionImple < ac, BasicAction: af42a1f:a6a:46efb7c6:728 status: ActionStatus.ABORT_ONLY >; - nested throwable: (javax.resource.ResourceException: Transaction is not active: tx=TransactionImple < ac, BasicAction: af42a1f:a6a:46efb7c6:728 status: ActionStatus.ABORT_ONLY >)
       at org.jboss.resource.adapter.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:94)
       at org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider.getConnection(InjectedDataSourceConnectionProvider.java:47)
       at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:423)
       ... 147 more
      Caused by: javax.resource.ResourceException: Transaction is not active: tx=TransactionImple < ac, BasicAction: af42a1f:a6a:46efb7c6:728 status: ActionStatus.ABORT_ONLY >
       at org.jboss.resource.connectionmanager.TxConnectionManager.getManagedConnection(TxConnectionManager.java:304)


      Have any of you had any experience in handling constraints with EJB3 and/or Seam? What am I supposed to do to recover from the exception and create a new transaction/session?

        • 1. Re: Recovering from a Constraint violation exception
          Fernando Montaño Expert

          I do use a Action + Service pattern in order to catch all EJB/JPA exceptions and stay in the same page or display a pretty nice error messages. The action is a simple POJO and the Service is an @EJB , @TransactionAttribute(REQUIRES_NEW) over the method makes me happy in this case.

          IIRC, I've already post in this forum how I'm doing (time ago).


          HTH.

          • 2. Re: Recovering from a Constraint violation exception
            Jason Long Master

            I do this validation manually and add a message to that control if the value already exists.

            I am not using Hibernate Validator at all. In every action that requires validation, I do this. This handles all complex cases that I have come across.

            Does anyone know if it is possible to bind a method of a seam component directly to the view for validation?

            Something like the following

            <h:inputText id="#{myId}" value="#{myValue}" converter="#{myValue.validateMyValue}"/>


            Currently I am using

            public static int addMessages(Map<String, String> m)
             {
             for(String key : m.keySet())
             {
             if(key.startsWith("globalMessage"))
             {
             FacesMessages.instance().add(m.get(key));
             }
             else
             {
             FacesMessages.instance().addToControl(key, m.get(key));
             }
             }
             return m.size();
             }


            And use this as follows

            private boolean isValid()
             {
             HashMap<String, String> errorMessages = new HashMap<String, String>();
            
            
             ValidatonUtil.checkNull("condition",
             poPipe.getCondition(),
             "Condition required!",
             errorMessages);
            
             ValidatonUtil.checkUniquePONuml("poNum",
             poPipe.getPoNum(),
             "You PO # must be unique!",
             errorMessages);
            
             ValidatonUtil.checkPositiveDouble("amountOrdered",
             poPipe.getAmountOrdered(),
             "Postive amount required!",
             errorMessages);
            
             ValidatonUtil.checkDateRealistic("date",
             poPipe.getDate(),
             "Date required!",
             errorMessages);
            
             ValidatonUtil.checkDateRealistic("dateAvailable",
             poPipe.getDatePromised(),
             "Date Available required!",
             errorMessages);
            
             return (ValidatonUtil.addMessages(errorMessages)==0) ? true : false;
             }


            I call a method like this every time I need to validate. These messages are added after jsf validations. If for example "0www8" is entered into a numeric field JSF messages appear and mine do not. I would like for all of these validations to occur at the same time. I would also like to not have to know the id of the component I want to attach the messages. If I could specify the method to use to validate and put it on the input field, I would like this to be tied together automatically.

            Is this possible and could someone point me to an example?

            • 3. Re: Recovering from a Constraint violation exception
              Alex Ka Novice

              fernando_jmt: Could you please post a link of the topic you're talking about. I couldn't find it in the forum.

              supernovasoftware.com: Manual and Hibernate Validation are one thing. Database constraints are another thing. Currently I have a problem handling exceptions from the database. One could argue if custom checks are secure enough...

              • 4. Re: Recovering from a Constraint violation exception
                Jason Long Master

                I have many many database constraints. I am just checking for possible errors before they happen.

                If they do then the user gets a nice message. If I for got to check one and it fails the users cry and I quickly add it so they are not hosed by an error screen.

                • 5. Re: Recovering from a Constraint violation exception
                  Alex Ka Novice

                  If you put it this way then yes... your solution seams good.

                  But I would like to have the check only once. Say as a DB constraint. Otherwise I'll be doing twice the same verification.

                  Sometimes it's easier and faster to implement a db constraint and if you try to mirror that check in the code it would require a query or two and some logical checks. This looks a bit inefficient in my opinion.



                  FYI The discussion on the transaction management continued here:
                  http://www.jboss.com/index.html?module=bb&op=viewtopic&t=117437