5 Replies Latest reply on Mar 2, 2009 3:43 PM by Guillaume Jeudy

    Business Key Validation and Seam

    Guillaume Jeudy Master

      Hi,


      I'm using Seam 2.0.1.GA in a typical JBoss 4.2.2 setup. I hit a problem where I need to validate attempts to insert duplicate entries for a particular entity. I use the business key (which is not the same as the database surrogate key). That business key includes a date range which makes it impossible to enforce at the database level unless we code a trigger which we don't want.


      So here I am trying to find a way to plug this validation in the Seam app layer.


      Plan A

      I could write custom validation as part of the business logic invoked in the INVOKE APPLICATION phase, the problem I have is since i'm operating in AUTO FLUSH mode and that the backing bean is also a hibernate managed entity I risk of flushing an invalid change to the database even after a validation failure.


      I don't use MANUAL flush (now im thinking maybe I should) because I didnt want to worry about flushing and one requirement of the application is to commit changes often to avoid changes that are lost in an abandoned or timed out conversation so it made sense to keep AUTO flush.


      Plan B

      On the other hand it seems that locating my business key validation inside a JSF validator would keep the backing bean clean in case of a validation failure (therefore no risks of committing invalid data). I added a validator bound to a hidden field so that it is only triggered when the whole form is submitted.


      The problem I find is that I need to lookup every single field from the JSF UI tree. Moreover the JSF UI Tree lookup logic will vary depending if we are validating inside a JSF dataTable or just a simple form or one of the more complex constructs like Richfaces listShuttle.


      That seems doable but doesn't sound like a simple or elegant solution.


      Plan C

        Use DTO objects for backing beans, invoke validation in INVOKE APPLICATION phase, upon successful pass copy DTO to hibernate managed entities. Yuck...


      All in all it seems like the logical solution would be Plan B.. I know that Beans Validation spec is evolving to address more complex validation scenarios but until we get there what can we do?


      How others have tackle this common problem?


      Thanks,
      -Guillaume

        • 1. Re: Business Key Validation and Seam
          Igor Stockler Newbie

          Hi Guillaume,


          I have implemented a solution based on your option A except for the fact that my validation logic was actually inside the entity object. This way you ensure consistency in your entity integrity across the whole application.


          This was done coding a validator method annotated with @AssertTrue in the entity. This works particularly well if your business validation logic don't depended specifically on one field, as it is almost always the case I think.


          The only problem was that seam didn't cater for those @AssertTrue validation errors, throwing an exception when persisting. If you look at this post, you can use an interceptor to validate and post validation messages back into the user interface. Therefore, you only need to annotate method calls that cause update/persist operations to trigger validation.


          I'm not sure if this code should be part of Seam, but definetely is lacking support for business validation in this scenario.


          Cheers

          • 2. Re: Business Key Validation and Seam
            Stuart Douglas Master

            You could write an entity listener to check for the existance of the key, however because you cannot use EntityManager methods in a entity listener you would have to do it by either acquiring a new EntityManager in the entityLister or by using jdbc directly (do not use the seam managed persistence context, it won't work). This would ensure that you never commit invalid data to the database.


            The problem with Igor's solution is that hibernate validator is implemented using entity listeners, so if you try and use the entityManager (or even cause a lazy collection or association to load) in your validator you will run into problems, which generally manifest as a stack overflow.


            Stuart

            • 3. Re: Business Key Validation and Seam
              Guillaume Jeudy Master

              Thanks guys for your interest.


              Let me point out the problems I have with your proposals, I assume that you are calling hibernate validator from the INVOKE APPLICATION phase. In my usecase its already too late because the submitted values were already applied to the managed entities. I'm using SMPC so the entities if they are being edited will automatically persist the changes to the database because i'm using AUTO flush mode.


              Like Igor pointed out triggering hibernate validator while the entities are being persisted is not acceptable because the user feedback would translate to a java exception.


              The @AssertTrue approach with invocation from an interceptor seems like an interesting approach because it gives a way to post a user friendly error message in the UI. However, I don't think that would work in my case because again that logic is invoked from INVOKE APPLICATION and the implicit dirty checking of my managed entities would still flush changes to the database.


              In short if I want to make your proposals work I would have to change to MANUAL flush mode and insert flush() calls in appropriate places in my code. I might also get to a point where validation failed but invalid values were still applied to the entities but are not persisted making the in-memory and persisted copies of the entities out of sync...


              I am still looking at Plan B, if your proposals can be applied from the PROCESS VALIDATIONS phase please let me know (and also give more details) because it would perfectly fit my situation.


              Thank you!
              Guillaume

              • 4. Re: Business Key Validation and Seam
                Ingo Jobling Master

                IMHO, Plan B, walking he JSF tree, is the best fit with the JSF cycle.  If you can position your hidden field so that the related fields are easily accessible, so much the better.


                An interesting alternative is to use the binding attribute, which lets you bind the actual JSF controls to a backing bean (must be in event scope).  In my case walking the tree turned out to be cleaner, but the technique of binding the components is quite powerful.  If you have not done so already, you might want to refer to Rick Hightower's blog, or Core JSF (Horstmann), or JSF Complete Ref. (Burns) for details of this technique as well as other possible approaches.


                I am looking forward to JSR-303 and its integration with JSF 2.  It should make this sort of thing much easier.


                BTW, I do feel that if integrity is important you really can't afford to use auto flush. Maybe I am just old fashioned, but I think that the user needs to confirm by pressing the save button, which results in a flush if and only if validation, as well as all other processing, is successful.


                • 5. Re: Business Key Validation and Seam
                  Guillaume Jeudy Master

                  Ingo, thanks for your feedback I appreciate it,


                  I already have a partial solution implemented walking the tree. It seems like it's easier to build a generic validator parametrizable with f:attribute to walk the tree and work with clientIds instead of using the binding solution. I will take a closer look at binding as it could be useful the next time I hit that problem.