2 Replies Latest reply on Aug 3, 2006 5:48 PM by andrew.rw.robinson

    Unique validation?

    andrew.rw.robinson

      I would like to have unique validation for a user object's username in a JSF page. Ideally, it will create a faces message and mark the UI input component as not valid when not unique. It should allow the value if the object is the same and the property hasn't changed (the user found in the database is the current user)

      The EBQL:
      select u from User u where u.username = :username

      I tried to create a validation method on my session bean, but Seam's exception filter caught my ValidationException and threw up an error page instead of letting the validation error pass through.

      I also though of creating a JSF validator or a hibernate validator, but neither let me access the object, only the value (so I can't check if the username already belongs to the current user).

      I don't want to put this code in my action method if I can help it as that would cause the error to only appear after all validations pass and I don't want the user to enter everything, clear all validation messages then get one more.

      Has anyone done this, or does anyone have a good way of implementing this?

      Here is the code I started for the hibernate validator, but got stuck at the "TODO":

      @ValidatorClass(CompareToValidator.class)
      @Target({ElementType.METHOD, ElementType.FIELD})
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      public @interface Unique
      {
       String ebql();
       String paramName() default "value";
       String message() default "{valid.unique}";
      }
      

      public class UniqueValidator
       implements Serializable, Validator<Unique>
      {
       private String ebql;
       private String paramName;
      
       /**
       * @see org.hibernate.validator.Validator#initialize(A)
       */
       public void initialize(Unique parameters)
       {
       ebql = parameters.ebql();
       paramName = parameters.paramName();
       }
      
       /**
       * @see org.hibernate.validator.Validator#isValid(java.lang.Object)
       */
       public boolean isValid(Object value)
       {
       UserTransaction utx = null;
       try { utx = Transactions.getUserTransaction(); } catch (NamingException ex) { return false; }
      
       try
       {
       utx.begin();
       utx.setRollbackOnly();
       EntityManager entityManager = null;
      
       entityManager = (EntityManager)
       Naming.getInitialContext().lookup("java:/entityManager");
       Query query = entityManager.createQuery(ebql).setParameter(paramName, value);
      
       List<?> list = query.getResultList();
       if (list.isEmpty()) return true;
      
       // TODO: validate the user is not the same
      
       return false;
       }
       catch (Exception ex)
       {
       try { utx.rollback(); } catch (Exception ex2) {}
       }
       return false;
       }
      }


      @AccessType("field")
      @Entity
      @Table(name="site_user")
      @Name("user")
      @Scope(ScopeType.SESSION)
      @SequenceGenerator(name="seq", sequenceName="site_user_seq")
      public class User
       implements Serializable, Comparable<User>
      {
       // Fields
       @Id
       @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")
       private Integer id;
      
       @Basic
       @NotNull(message="{valid.user.username.notnull}")
       @Length(max=25,min=4,message="{valid.user.username.length}")
       @Unique(ebql="select u from User where u.username = :value")
       private String username;
      ...
      


        • 1. Re: Unique validation?
          pmuir

          What about writing a JSF validator that allows you to specify the current username (or user object) as a parameter:

          <my:validateUnique oldValue="#{user.username}" />


          The logic would be something like:

          if (value == oldValue) {
           return true;
          } else {
           // get the list
           return list.isEmpty();
          }


          (NB I've not tested this idea)

          • 2. Re: Unique validation?
            andrew.rw.robinson

            That would probably work. I also realized that I could just not throw a validation exception (Found out it isn't required, you can add the message to the faces context directly instead) also. In the end I decided to go with less functionality to save time and just put the code in the action method. Not as nice, but easy to code.

            Thanks